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.c (282044B)


      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  * L2 - Broadcom StrataSwitch Layer-2 switch API.
      8  */
      9 
     10 #include <sal/core/libc.h>
     11 #include <shared/bsl.h>
     12 #include <soc/mem.h>
     13 #include <soc/profile_mem.h>
     14 #include <soc/debug.h>
     15 #include <soc/drv.h>
     16 #include <soc/l2x.h>
     17 #if defined(BCM_TRIUMPH3_SUPPORT)
     18 #include <soc/triumph3.h>
     19 #endif /* BCM_TRIUMPH3_SUPPORT */
     20 #ifdef BCM_WARM_BOOT_SUPPORT
     21 #include <soc/scache.h>
     22 #endif /* BCM_WARM_BOOT_SUPPORT */
     23 
     24 #include <bcm/l2.h>
     25 #include <bcm/error.h>
     26 
     27 #include <bcm_int/esw/mbcm.h>
     28 #include <bcm_int/esw/l2.h>
     29 #include <bcm_int/esw/vlan.h>
     30 #include <bcm_int/esw/trunk.h>
     31 #include <bcm_int/esw/stack.h>
     32 #if defined(BCM_FIREBOLT_SUPPORT)
     33 #include <bcm_int/esw/firebolt.h>	  
     34 #endif /* BCM_FIREBOLT_SUPPORT */
     35 #if defined(BCM_TRX_SUPPORT)
     36 #include <bcm_int/esw/triumph.h>
     37 #include <bcm_int/esw/trx.h>
     38 #include <bcm_int/esw/virtual.h>
     39 #include <soc/triumph.h>
     40 #endif /* BCM_TRX_SUPPORT */
     41 #include <bcm_int/esw/mpls.h>
     42 #include <bcm_int/esw/mim.h>
     43 #include <bcm_int/esw/trident.h>
     44 #if defined(BCM_TRIUMPH3_SUPPORT)
     45 #include <bcm_int/esw/triumph3.h>
     46 #endif /* BCM_TRIUMPH3_SUPPORT */
     47 #if defined(BCM_TRIDENT2_SUPPORT)
     48 #include <soc/trident2.h>
     49 #include <bcm_int/esw/trident2.h>
     50 #endif /* BCM_TRIDENT2_SUPPORT */
     51 #if defined(BCM_KATANA2_SUPPORT)
     52 #include <bcm_int/esw/subport.h>
     53 #include <bcm_int/esw/katana2.h>
     54 #endif /* BCM_KATANA2_SUPPORT */
     55 #if defined(BCM_HURRICANE3_SUPPORT)
     56 #include <soc/hurricane3.h>
     57 #endif /* BCM_HURRICANE3_SUPPORT */
     58 #if defined(BCM_GREYHOUND2_SUPPORT)
     59 #include <soc/greyhound2.h>
     60 #endif /* BCM_GREYHOUND2_SUPPORT */
     61 #if defined(BCM_HGPROXY_COE_SUPPORT)
     62 #include <bcm_int/esw/xgs5.h>
     63 #endif /* BCM_HGPROXY_COE_SUPPORT */
     64 #ifdef BCM_WARM_BOOT_SUPPORT
     65 #include <bcm_int/esw/switch.h>
     66 #endif /* BCM_WARM_BOOT_SUPPORT */
     67 #if defined(BCM_TRIDENT3_SUPPORT)
     68 #include <soc/esw/flow_db.h>
     69 #include <bcm_int/esw/trident3.h>
     70 #endif /* BCM_TRIDENT3_SUPPORT */
     71 
     72 #if defined(BCM_TSN_SUPPORT)
     73 #include <bcm_int/esw/tsn.h>
     74 #endif /* BCM_TSN_SUPPORT */
     75 
     76 #include <bcm_int/esw_dispatch.h>
     77 #if defined(BCM_TOMAHAWK3_SUPPORT)
     78 #include <bcm_int/tomahawk3_dispatch.h>
     79 #include <bcm_int/esw/tomahawk3.h>
     80 #endif /* BCM_TOMAHAWK3_SUPPORT */
     81 
     82 /****************************************************************
     83  *
     84  * L2 software tables, per unit.
     85  */
     86 
     87 int _l2_init[BCM_MAX_NUM_UNITS];
     88 
     89 #if defined(BCM_TRX_SUPPORT)
     90 STATIC soc_profile_mem_t *_bcm_l2_port_cbl_profile[BCM_MAX_NUM_UNITS];
     91 #endif /* BCM_TRX_SUPPORT */
     92 _bcm_l2_match_ctrl_t *_bcm_l2_match_ctrl[BCM_MAX_NUM_UNITS];
     93 
     94 /****************************************************************
     95  *
     96  * L2 learn limit software representation, per unit.
     97  */
     98 
     99 #define BCM_MAC_LIMIT_MAX   (soc_mem_index_count(unit, L2Xm) - 1)
    100 
    101 /* forward declaration */
    102 static int _bcm_l2_bpdu_init(int unit);
    103 STATIC int _bcm_esw_l2_replace(int unit, uint32 flags, uint32 int_flags,
    104                                bcm_l2_addr_t *match_addr,
    105                                bcm_module_t new_module, bcm_port_t new_port, 
    106                                bcm_trunk_t new_trunk,
    107                                bcm_l2_traverse_cb trav_fn, void *user_data);
    108 #if defined(BCM_TRX_SUPPORT) || defined(BCM_RAPTOR_SUPPORT)
    109 STATIC int _bcm_l2_learn_limit_init(int unit);
    110 STATIC int _bcm_l2_learn_limit_porttrunk_set(int unit, int port_tgid, 
    111                                              uint32 flags, int limit);
    112 STATIC int _bcm_l2_learn_limit_port_set(int unit, bcm_port_t port,
    113                                         uint32 flags, int limit);
    114 STATIC int _bcm_l2_learn_limit_trunk_set(int unit, bcm_trunk_t trunk,
    115                                          uint32 flags, int limit);
    116 #endif /* BCM_TRX_SUPPORT || BCM_RAPTOR_SUPPORT */
    117 
    118 /* L2 (vlan, port) tuple structure */
    119 typedef struct _bcm_l2_vlan_port_pair_s {
    120     /* Array of PBMP with max VLAN size, the first 0-4095 PBMP entries 
    121      in the array are for max number of VLANs supported, the 4096th
    122      i.e pbm[BCM_VLAN_MAX+1]th entry in the array is to maintain a list
    123      of PBMPs for invalid VLANs (used for delete by gport operation). */
    124     bcm_pbmp_t        pbm[BCM_VLAN_MAX+2]; 
    125 } _bcm_l2_vlan_port_pair_t;
    126 
    127 typedef struct _bcm_l2_vlan_trunk_pair_s {
    128     SHR_BITDCL        *tbm[BCM_VLAN_MAX+2];
    129 } _bcm_l2_vlan_trunk_pair_t;
    130 
    131 typedef struct _bcm_l2_vlan_vp_pair_s {
    132     SHR_BITDCL        *vpbm[BCM_VLAN_MAX+2];
    133 } _bcm_l2_vlan_vp_pair_t;
    134 
    135 typedef struct _bcm_l2_del_vlan_port_pair_s {
    136     uint32                    flags;            /* BCM_L2_AUTH_XXX flags. */
    137     uint32                    replace_flags;        /* BCM_L2_REPLACE_XXX flags */
    138     bcm_vlan_vector_t         del_by_vlan_vec;  /* Vlan vector represents 
    139                                                    delete by vlan */
    140     _bcm_l2_vlan_port_pair_t  *mod_pair_arr;    /* Reference to Array of
    141                                                    (vlan,port) for max modules */
    142     _bcm_l2_vlan_trunk_pair_t *unit_pair_arr;   /* Reference to Array of
    143                                                    (vlan,tid) for each unit */
    144     _bcm_l2_vlan_vp_pair_t    *vp_pair_arr;     /* Reference to Array of
    145                                                    (vlan,vp) for each unit */
    146     SHR_BITDCL                **vfi_pair_arr;     /* Reference to Array of
    147                                                    (vfi,vp) for each unit */
    148     SHR_BITDCL                *del_by_vfi_vec;  /* VFI vector */
    149 } _bcm_l2_del_vlan_port_pair_t;
    150 
    151 typedef enum l2x_memacc_field_e {
    152     _BCM_L2_MEMACC_VALID,
    153     _BCM_L2_MEMACC_KEY_TYPE,
    154     _BCM_L2_MEMACC_NUM
    155 } l2x_memacc_field_t;
    156 
    157 STATIC uint32 _l2_dbg_matched_entries[SOC_MAX_NUM_DEVICES], 
    158               _l2_dbg_unmatched_entries[SOC_MAX_NUM_DEVICES];
    159 
    160 #ifdef BCM_WARM_BOOT_SUPPORT
    161 STATIC int _bcm_esw_l2_wb_alloc(int unit);
    162 STATIC int _bcm_esw_l2_wb_recover(int unit);
    163 #endif /* BCM_WARM_BOOT_SUPPORT */
    164 
    165 /* just need to clear SRC or DES hit bit. Customers may call API bcm_esw_l2_replace
    166 *  with parameter *match_addr which value is NULL */
    167 #define _CLEAR_ALL_ENTRIES_SRC_OR_DES_HIT_BIT(flag) \
    168                   (!(flag & (BCM_L2_REPLACE_MATCH_VLAN |\
    169                              BCM_L2_REPLACE_MATCH_MAC |\
    170                              BCM_L2_REPLACE_MATCH_DEST)) &&\
    171                    (flag & (BCM_L2_REPLACE_DES_HIT_CLEAR |\
    172                             BCM_L2_REPLACE_SRC_HIT_CLEAR)))
    173 /*
    174  * Function:
    175  *	_bcm_esw_l2_gport_parse
    176  * Description:
    177  *	Parse gport in the l2 table
    178  * Parameters:
    179  *	unit -      [IN] StrataSwitch PCI device unit number (driver internal).
    180  *  l2addr -    [IN/OUT] l2 addr structure to parse and fill
    181  *  sub_port -  [OUT] Virtual port group (-1 if not supported)
    182  *  mpls_port - [OUT] MPLS port (-1 if not supported)
    183  * Returns:
    184  *	BCM_E_XXX
    185  */
    186 int 
    187 _bcm_esw_l2_gport_parse(int unit, bcm_l2_addr_t *l2addr, 
    188                         _bcm_l2_gport_params_t *params)
    189 {
    190     int             id;
    191     bcm_port_t      _port;
    192     bcm_trunk_t     _trunk;
    193     bcm_module_t    _modid, _mymodid;
    194 
    195     if ((NULL == l2addr) || (NULL == params)){
    196         return BCM_E_PARAM;
    197     }
    198 
    199     params->param0 = -1;
    200     params->param1 = -1;
    201     params->type = 0;
    202 
    203     BCM_IF_ERROR_RETURN(
    204         _bcm_esw_gport_resolve(unit, l2addr->port, &_modid, &_port, 
    205                                &_trunk, &id));
    206 
    207     BCM_IF_ERROR_RETURN(
    208         bcm_esw_stk_my_modid_get(unit, &_mymodid));
    209 
    210 
    211     if ((BCM_TRUNK_INVALID != _trunk) && (-1 == id)) {
    212         params->param0 = _trunk;
    213         params->type = _SHR_GPORT_TYPE_TRUNK;
    214         return BCM_E_NONE;
    215     }
    216 
    217     if ((-1 != _port) && (-1 == id)) {
    218         params->param0 = _port;
    219         if ((_port == CMIC_PORT(unit)) && (_modid == _mymodid)) {
    220             params->type = _SHR_GPORT_TYPE_LOCAL_CPU;
    221             return BCM_E_NONE;
    222         }
    223         params->param1 = _modid;
    224         params->type = _SHR_GPORT_TYPE_MODPORT;
    225         return BCM_E_NONE;
    226     }
    227 
    228     if (-1 != id) {
    229         params->param0 = id;
    230         if (BCM_GPORT_IS_SUBPORT_GROUP(l2addr->port)) {
    231             params->type = _SHR_GPORT_TYPE_SUBPORT_GROUP;
    232         } else if (BCM_GPORT_IS_SUBPORT_PORT(l2addr->port)) {
    233             params->type = _SHR_GPORT_TYPE_SUBPORT_PORT;
    234 
    235 #if defined(BCM_HGPROXY_COE_SUPPORT)
    236             if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
    237                 _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, l2addr->port)) {
    238                 params->param0 = _port;
    239                 params->param1 = _modid;
    240             }
    241 #endif
    242 #if defined(BCM_KATANA2_SUPPORT)
    243             if (_BCM_KT2_GPORT_IS_LINKPHY_OR_SUBTAG_SUBPORT_GPORT(unit,
    244                 l2addr->port)) {
    245                 params->param0 = _port;
    246                 params->param1 = _modid;
    247             }
    248 #endif
    249         } else if (BCM_GPORT_IS_MPLS_PORT(l2addr->port)){
    250             params->type = _SHR_GPORT_TYPE_MPLS_PORT;
    251         } else if (BCM_GPORT_IS_MIM_PORT(l2addr->port)){
    252             params->type = _SHR_GPORT_TYPE_MIM_PORT;
    253         } else if (BCM_GPORT_IS_WLAN_PORT(l2addr->port)){
    254             params->type = _SHR_GPORT_TYPE_WLAN_PORT;
    255         } else if (BCM_GPORT_IS_TRILL_PORT(l2addr->port)){
    256             params->type = _SHR_GPORT_TYPE_TRILL_PORT;
    257         } else if (BCM_GPORT_IS_VLAN_PORT(l2addr->port)){
    258             params->type = _SHR_GPORT_TYPE_VLAN_PORT;
    259         } else if (BCM_GPORT_IS_NIV_PORT(l2addr->port)){
    260             params->type = _SHR_GPORT_TYPE_NIV_PORT;
    261         } else if (BCM_GPORT_IS_L2GRE_PORT(l2addr->port)){
    262             params->type = _SHR_GPORT_TYPE_L2GRE_PORT;
    263         } else if (BCM_GPORT_IS_VXLAN_PORT(l2addr->port)){
    264             params->type = _SHR_GPORT_TYPE_VXLAN_PORT;
    265         } else if (BCM_GPORT_IS_FLOW_PORT(l2addr->port)){
    266             params->type = _SHR_GPORT_TYPE_FLOW_PORT;
    267         } else if (BCM_GPORT_IS_EXTENDER_PORT(l2addr->port)){
    268             params->type = _SHR_GPORT_TYPE_EXTENDER_PORT;
    269         }
    270 
    271         return BCM_E_NONE;
    272     } else if (BCM_GPORT_IS_BLACK_HOLE(l2addr->port)) {
    273        params->type = _SHR_GPORT_TYPE_BLACK_HOLE;
    274        params->param0 = 0;
    275        params->param1 = id;
    276 
    277        return BCM_E_NONE;
    278     }
    279 
    280     return BCM_E_PORT;
    281 }
    282 
    283 /*
    284  * Function:
    285  *	bcm_esw_l2_init
    286  * Description:
    287  *	Perform required initializations to L2 table.
    288  * Parameters:
    289  *	unit - StrataSwitch PCI device unit number (driver internal).
    290  * Returns:
    291  *	BCM_E_XXX
    292  */
    293 
    294 int
    295 bcm_esw_l2_init(int unit)
    296 {
    297     int rv; 
    298 #ifdef BCM_XGS_SWITCH_SUPPORT
    299     int frozen;
    300 
    301 #if defined(BCM_TOMAHAWK3_SUPPORT)
    302     /* Added to handle SDK functions calling esw version,
    303      * instead of Tomahawk3's version
    304      */
    305     if (SOC_IS_TOMAHAWK3(unit)) {
    306         return bcm_tomahawk3_l2_init(unit);
    307     }
    308 #endif /* BCM_TOMAHAWK3_SUPPORT  */
    309 
    310 #if defined(BCM_TRIUMPH3_SUPPORT)
    311     if (soc_feature(unit, soc_feature_ism_memory)) {
    312          BCM_IF_ERROR_RETURN(bcm_tr3_l2_init(unit));
    313 #ifdef BCM_WARM_BOOT_SUPPORT
    314         if (SOC_WARM_BOOT(unit)) {
    315             BCM_IF_ERROR_RETURN(_bcm_esw_l2_wb_recover(unit));
    316         } else {
    317             BCM_IF_ERROR_RETURN(_bcm_esw_l2_wb_alloc(unit));
    318         }
    319 #endif /* BCM_WARM_BOOT_SUPPORT */
    320          _l2_init[unit] = 1;		/* some positive value */
    321          return BCM_E_NONE;
    322     }
    323 #endif /* BCM_TRIUMPH3_SUPPORT */    
    324 
    325     BCM_IF_ERROR_RETURN(
    326         soc_l2x_is_frozen(unit, SOC_L2X_FROZEN_WITH_LOCK, &frozen));
    327     if (TRUE == frozen) {
    328         return BCM_E_BUSY;
    329     }
    330 #endif /* BCM_XGS_SWITCH_SUPPORT */
    331     _l2_init[unit] = 0;
    332 
    333 #ifdef BCM_SHADOW_SUPPORT
    334     if (soc_feature(unit, soc_feature_no_bridging)) {
    335         return BCM_E_NONE;
    336     }
    337 #endif
    338 
    339     if (SOC_IS_XGS_FABRIC(unit) && !SOC_IS_TITAN2X(unit)&& !SOC_IS_TOMAHAWK2(unit)) {        
    340         _l2_init[unit] = BCM_E_UNAVAIL;
    341         return BCM_E_NONE;
    342     }
    343 
    344     if (!SOC_WARM_BOOT(unit) && !SOC_IS_RCPU_ONLY(unit)) {
    345         /* Turn off arl aging */
    346         BCM_IF_ERROR_RETURN
    347             (SOC_FUNCTIONS(unit)->soc_age_timer_set(unit, 0, 0));
    348 
    349         bcm_esw_l2_detach(unit);
    350     }
    351     /* Proposal: during warm boot, customer wants to freeze l2x. 
    352     * After warm boot, customer will restore l2x.
    353     */
    354 #ifdef BCM_TRIDENT2_SUPPORT
    355     if (SOC_IS_TD2_TT2(unit) && SOC_WARM_BOOT(unit) &&
    356         soc_l2x_cml_override_is_enabled(unit)) {
    357         /* In this condition, soc_l2x_freeze does not change ING_MISC_CONFIG2r.
    358         * It just wants to Increment  l2 frozen indicator "f_l2->hw_frozen++". When we call
    359         * bcm_esw_l2_age_timer_set, we won't enable SW aging by mistake.
    360         */
    361         BCM_IF_ERROR_RETURN(soc_l2x_selective_freeze(unit, SOC_L2X_FROZEN_WITHOUT_LOCK));
    362     }
    363 #endif /* BCM_TRIDENT2_SUPPORT */
    364 
    365     /*
    366      * Call chip-dependent initialization
    367      */
    368     BCM_IF_ERROR_RETURN
    369         (mbcm_driver[unit]->mbcm_l2_init(unit));
    370 
    371     if (!SOC_WARM_BOOT(unit) && !SOC_IS_RCPU_ONLY(unit)) {
    372         if (!soc_feature(unit, soc_feature_l2_user_table)) {
    373             /*
    374              * Init BPDU station address registers.
    375              */
    376             rv = _bcm_l2_bpdu_init(unit);
    377             if (BCM_FAILURE(rv) && (rv != BCM_E_UNAVAIL)) {
    378                 return rv;
    379             }
    380         }
    381 
    382         /*
    383          * Init L2 cache
    384          */
    385         rv = bcm_esw_l2_cache_init(unit);
    386         if (BCM_FAILURE(rv) && (rv != BCM_E_UNAVAIL)) {
    387             return rv;
    388         }
    389     }
    390 
    391     /*
    392      * Init L2 learn limit
    393      */
    394 #if defined(BCM_TRIUMPH_SUPPORT) || defined(BCM_RAPTOR_SUPPORT)
    395     rv = _bcm_l2_learn_limit_init(unit);
    396     if (BCM_FAILURE(rv) && (rv != BCM_E_UNAVAIL)) {
    397         return rv;
    398     }
    399 #endif /* BCM_TRIUMPH_SUPPORT  || BCM_RAPTOR_SUPPORT */
    400 #if defined(BCM_TRX_SUPPORT)
    401     /*
    402      * Init class based learning
    403      */
    404     if (soc_feature(unit, soc_feature_class_based_learning)) {
    405         soc_mem_t mem;
    406         int entry_words;
    407         int index_max;
    408         int lclass;
    409         union {
    410             port_cbl_table_entry_t port_cbl[256];
    411             uint32 w[1];
    412         } entry;
    413         void *entries[1];
    414         soc_profile_mem_t *profile;
    415         int module;
    416         uint32 profile_index;
    417         int field_len;
    418 
    419         /* Clear CBL attribute register and CBL table */
    420         if (SOC_REG_IS_VALID(unit, CBL_ATTRIBUTEr) && (!SOC_WARM_BOOT(unit))) {
    421             for (lclass = 0; lclass < SOC_REG_NUMELS(unit, CBL_ATTRIBUTEr);
    422                  lclass++) {
    423                 BCM_IF_ERROR_RETURN(WRITE_CBL_ATTRIBUTEr(unit, lclass, 0));
    424             }
    425         }
    426 
    427         if (!SOC_WARM_BOOT(unit)) {
    428             BCM_IF_ERROR_RETURN(soc_mem_clear(unit, PORT_CBL_TABLEm,
    429                                                  COPYNO_ALL, FALSE));
    430         }
    431         if (soc_mem_is_valid(unit, PORT_CBL_TABLE_MODBASEm)) {
    432             /* Create profile for PORT_CBL_TABLE table */
    433             if (_bcm_l2_port_cbl_profile[unit] == NULL) {
    434                 _bcm_l2_port_cbl_profile[unit] =
    435                     sal_alloc(sizeof(soc_profile_mem_t),
    436                               "PORT_CBL_TABLE profile");
    437                 if (_bcm_l2_port_cbl_profile[unit] == NULL) {
    438                     return BCM_E_MEMORY;
    439                 }
    440                 soc_profile_mem_t_init(_bcm_l2_port_cbl_profile[unit]);
    441             }
    442             profile = _bcm_l2_port_cbl_profile[unit];
    443             mem = PORT_CBL_TABLEm;
    444             entry_words = sizeof(port_cbl_table_entry_t) / sizeof(uint32);
    445             field_len = soc_mem_field_length(unit, PORT_CBL_TABLE_MODBASEm,
    446                                              BASEf);
    447             index_max = (1 << field_len) - 1;
    448             entries[0] = &entry;
    449             sal_memset(&entry.port_cbl[0], 0, sizeof(entry.port_cbl[0]));
    450             field_len = soc_mem_field_length(unit, PORT_CBL_TABLEm,
    451                                              PORT_LEARNING_CLASSf);
    452             soc_mem_field32_set(unit, PORT_CBL_TABLEm, &entry.port_cbl[0],
    453                                 PORT_LEARNING_CLASSf, (1 << field_len) - 1);
    454 
    455             BCM_IF_ERROR_RETURN
    456                 (soc_profile_mem_index_create(unit, &mem, &entry_words, NULL,
    457                                               &index_max, entries, 1,
    458                                               profile));
    459 
    460             if (!SOC_WARM_BOOT(unit)) {
    461                 BCM_IF_ERROR_RETURN(soc_mem_clear(unit, PORT_CBL_TABLE_MODBASEm,
    462                                             COPYNO_ALL, FALSE));
    463                 sal_memset(entry.port_cbl, 0, sizeof(entry.port_cbl));
    464                 BCM_IF_ERROR_RETURN
    465                     (soc_profile_mem_add(unit, profile, entries,
    466                                          SOC_PORT_ADDR_MAX(unit) + 1,
    467                                          &profile_index));
    468                 for (module = 1; module <= SOC_MODID_MAX(unit); module++) {
    469                     SOC_IF_ERROR_RETURN
    470                         (soc_profile_mem_reference
    471                          (unit, profile, profile_index,
    472                           SOC_PORT_ADDR_MAX(unit) + 1));
    473                 }
    474             }
    475 #ifdef BCM_WARM_BOOT_SUPPORT
    476             else {
    477                 port_cbl_table_modbase_entry_t base_entry;
    478 
    479                 for (module = 0; module <= SOC_MODID_MAX(unit); module++) {
    480                     SOC_IF_ERROR_RETURN
    481                         (soc_mem_read(unit, PORT_CBL_TABLE_MODBASEm,
    482                                       MEM_BLOCK_ANY, module, &base_entry));
    483                     profile_index =
    484                         soc_mem_field32_get(unit, PORT_CBL_TABLE_MODBASEm,
    485                                             &base_entry, BASEf);
    486                     SOC_IF_ERROR_RETURN
    487                         (soc_profile_mem_reference
    488                          (unit, profile, profile_index,
    489                           SOC_PORT_ADDR_MAX(unit) + 1));
    490                 }
    491             }
    492 #endif /* BCM_WARM_BOOT_SUPPORT */
    493         }
    494     }
    495 
    496 #endif /* BCM_TRX_SUPPORT */
    497 #ifdef BCM_WARM_BOOT_SUPPORT
    498     if (SOC_WARM_BOOT(unit)) {
    499         BCM_IF_ERROR_RETURN(_bcm_esw_l2_wb_recover(unit));
    500     } else {
    501         BCM_IF_ERROR_RETURN(_bcm_esw_l2_wb_alloc(unit));
    502     }
    503 #endif /* BCM_WARM_BOOT_SUPPORT */
    504     _l2_init[unit] = 1;		/* some positive value */
    505     return BCM_E_NONE;
    506 }
    507 
    508 /*
    509  * Function:
    510  *      bcm_esw_l2_detach
    511  * Purpose:
    512  *      Clean up l2 bcm layer when unit is detached
    513  * Parameters:
    514  *      unit - unit being detached
    515  * Returns:
    516  *	BCM_E_XXX
    517  */
    518 
    519 int
    520 bcm_esw_l2_detach(int unit)
    521 {
    522     
    523 #ifdef BCM_XGS_SWITCH_SUPPORT
    524     int frozen; 
    525 
    526 #if defined(BCM_TOMAHAWK3_SUPPORT)
    527     /* Added to handle SDK functions calling esw version,
    528      * instead of Tomahawk3's version
    529      */
    530     if (SOC_IS_TOMAHAWK3(unit)) {
    531         return bcm_tomahawk3_l2_detach(unit);
    532     }
    533 #endif /* BCM_TOMAHAWK3_SUPPORT  */
    534 
    535 #if defined(BCM_TRIUMPH3_SUPPORT)
    536     if (soc_feature(unit, soc_feature_ism_memory)) {
    537          BCM_IF_ERROR_RETURN(bcm_tr3_l2_detach(unit));
    538 
    539          _l2_init[unit] = 0;
    540          return BCM_E_NONE;
    541     }
    542 #endif /* BCM_TRIUMPH3_SUPPORT */    
    543 
    544     /* Verify the table is not frozen */
    545     BCM_IF_ERROR_RETURN(
    546         soc_l2x_is_frozen(unit, SOC_L2X_FROZEN_WITH_LOCK, &frozen));
    547     if (TRUE == frozen) {
    548         return BCM_E_BUSY;
    549     }
    550 #endif /* BCM_XGS_SWITCH_SUPPORT */
    551 
    552 #ifdef BCM_SHADOW_SUPPORT
    553     if (soc_feature(unit, soc_feature_no_bridging)) {
    554         return BCM_E_NONE;
    555     }
    556 #endif
    557 
    558     if (_bcm_l2_match_ctrl[unit] && _bcm_l2_match_ctrl[unit]->preserved) {
    559         _l2_init[unit] = 0;
    560         return BCM_E_NONE;
    561     }
    562 
    563     /*
    564      * Call chip-dependent finalization.
    565      */
    566     SOC_IF_ERROR_RETURN
    567 	(mbcm_driver[unit]->mbcm_l2_term(unit));
    568 
    569     _l2_init[unit] = 0;
    570     return BCM_E_NONE;
    571 }
    572 
    573 
    574 /*
    575  * Function:
    576  *	_bcm_esw_delete_replace_flags_convert
    577  * Description:
    578  *	A helper function to all delete_by APIs to use bcm_l2_replace. 
    579  *  Converts L2 flags to L2 replace flags compatable to use with bcm_l2_replace
    580  * Parameters:
    581  *	unit        [IN]- device unit
    582  *	flags       [IN] - BCM_L2_DELETE_XXX
    583  *	repl_flags  [OUT]- Vflags BCM_L2_REPLACE_XXX
    584  * Returns:
    585  *	BCM_E_XXX	
    586  */
    587 
    588 int 
    589 _bcm_esw_delete_replace_flags_convert(int unit, uint32 flags, uint32 *repl_flags)
    590 {
    591     uint32 tmp_flags = BCM_L2_REPLACE_DELETE;
    592 
    593     /* Age feature only supported by Bulk Control */
    594     if (soc_feature(unit, soc_feature_l2_bulk_control)) {
    595 
    596         /* Both Age and Delete flags cannot be specified */ 
    597         if ( (flags & BCM_L2_REPLACE_AGE) && (flags & BCM_L2_REPLACE_DELETE) ){
    598             return BCM_E_PARAM;
    599         }
    600 
    601         if (flags & BCM_L2_REPLACE_AGE){
    602             tmp_flags = BCM_L2_REPLACE_AGE;
    603         }
    604     } else {
    605         if (flags & BCM_L2_REPLACE_AGE){
    606             return BCM_E_UNAVAIL;
    607         }
    608     }
    609 
    610     if (flags & BCM_L2_DELETE_PENDING) {
    611         tmp_flags |= BCM_L2_REPLACE_PENDING;
    612     }
    613     if (flags & BCM_L2_DELETE_STATIC) {
    614         tmp_flags |= BCM_L2_REPLACE_MATCH_STATIC; 
    615     }
    616     if (flags & BCM_L2_DELETE_NO_CALLBACKS) {
    617         tmp_flags |= BCM_L2_REPLACE_NO_CALLBACKS;
    618     }
    619     if (flags & BCM_L2_REPLACE_VPN_TYPE) {
    620         tmp_flags |= BCM_L2_REPLACE_VPN_TYPE;
    621     }
    622     *repl_flags = tmp_flags;
    623     return BCM_E_NONE;
    624 }
    625 
    626 /*
    627  * Function:
    628  *	bcm_esw_l2_addr_add
    629  * Description:
    630  *	Add a MAC address to the Switch Address Resolution Logic (ARL)
    631  *	port with the given VLAN ID and parameters.
    632  * Parameters:
    633  *	unit - StrataSwitch PCI device unit number (driver internal).
    634  *	l2addr - Pointer to bcm_l2_addr_t containing all valid fields
    635  * Returns:
    636  *	BCM_E_NONE		Success
    637  *	BCM_E_INTERNAL		Chip access failure
    638  * Notes:
    639  *	Use CMIC_PORT(unit) to associate the entry with the CPU.
    640  *	Use flag of BCM_L2_COPY_TO_CPU to send a copy to the CPU.
    641  *      Use flag of BCM_L2_TRUNK_MEMBER to set trunking (TGID must be
    642  *      passed as well with non-zero trunk group ID)
    643  */
    644 
    645 int
    646 bcm_esw_l2_addr_add(int unit, bcm_l2_addr_t *l2addr)
    647 {
    648 #if defined(BCM_TOMAHAWK3_SUPPORT)
    649     /* Added to handle SDK functions calling esw version,
    650      * instead of Tomahawk3's version
    651      */
    652     if (SOC_IS_TOMAHAWK3(unit)) {
    653         return bcm_tomahawk3_l2_addr_add(unit, l2addr);
    654     }
    655 #endif /* BCM_TOMAHAWK3_SUPPORT  */
    656 
    657     L2_INIT(unit);
    658 
    659 #if defined(BCM_TRIUMPH3_SUPPORT)
    660     if (soc_feature(unit, soc_feature_ism_memory)) {
    661         return bcm_tr3_l2_addr_add(unit, l2addr);
    662     }
    663 #endif /* BCM_TRIUMPH3_SUPPORT */    
    664 
    665     /* Input parameters check. */
    666     if (NULL == l2addr) {
    667         return (BCM_E_PARAM);
    668     }
    669 
    670     if (!soc_feature(unit, soc_feature_l2_drop_mc_mac)) {
    671         if (l2addr->flags & BCM_L2_DISCARD_DST) {
    672             if (MAC_IS_MCAST(l2addr->mac)) {
    673                 return (BCM_E_UNAVAIL);
    674             }
    675         }
    676     }
    677 
    678     if (l2addr->flags & BCM_L2_LOCAL_CPU) {
    679         l2addr->port = CMIC_PORT(unit);
    680         BCM_IF_ERROR_RETURN(bcm_esw_stk_modid_get(unit, &l2addr->modid));
    681     }
    682 
    683     if (l2addr->flags & BCM_L2_TRUNK_MEMBER) {
    684         BCM_IF_ERROR_RETURN(
    685             _bcm_trunk_id_validate(unit, l2addr->tgid));
    686     }
    687 
    688     if (SOC_L2X_GROUP_ENABLE_GET(unit)) {
    689         if (soc_feature(unit, soc_feature_overlaid_address_class) && 
    690             !BCM_L2_PRE_SET(l2addr->flags)) {
    691             if ((l2addr->group > SOC_OVERLAID_ADDR_CLASS_MAX(unit)) ||
    692                 (l2addr->group < 0)) {
    693                 return (BCM_E_PARAM);
    694             }
    695         } else if ((l2addr->group > SOC_ADDR_CLASS_MAX(unit)) || 
    696                    (l2addr->group < 0)) {
    697             return (BCM_E_PARAM);
    698         }
    699         if (!BCM_PBMP_IS_NULL(l2addr->block_bitmap)) {
    700             return (BCM_E_PARAM);
    701         }
    702     } else {
    703         if (l2addr->group)  {
    704             return (BCM_E_PARAM);
    705         }
    706     }
    707 
    708     /* Input parameters check for TSN related parameters */
    709     if (!soc_feature(unit, soc_feature_tsn)) {
    710         if (l2addr->tsn_flowset) {
    711             return BCM_E_UNAVAIL;
    712         }
    713     }
    714 
    715     /* Input parameters check for SR related parameters */
    716     if (!soc_feature(unit, soc_feature_tsn_sr)) {
    717         if (l2addr->flags & BCM_L2_SR_SAN_DEST) {
    718             return BCM_E_UNAVAIL;
    719         }
    720         if (!BCM_PBMP_IS_NULL(l2addr->sa_source_filter_pbmp)) {
    721             return BCM_E_UNAVAIL;
    722         }
    723         if (l2addr->sr_flowset) {
    724             return BCM_E_UNAVAIL;
    725         }
    726     }
    727 
    728     SOC_IF_ERROR_RETURN
    729 	(mbcm_driver[unit]->mbcm_l2_addr_add(unit, l2addr));
    730 
    731     return BCM_E_NONE;
    732 }
    733 
    734 /*
    735  * Function:
    736  *	bcm_esw_l2_addr_delete
    737  * Description:
    738  *	Delete an L2 address (MAC+VLAN) from the device
    739  * Parameters:
    740  *	unit - device unit
    741  *	mac  - MAC address to delete
    742  *	vid  - VLAN id
    743  * Returns:
    744  *	BCM_E_XXX
    745  */
    746 
    747 int
    748 bcm_esw_l2_addr_delete(int unit, bcm_mac_t mac, bcm_vlan_t vid)
    749 {
    750 #if defined(BCM_TOMAHAWK3_SUPPORT)
    751     /* Added to handle SDK functions calling esw version,
    752      * instead of Tomahawk3's version
    753      */
    754     if (SOC_IS_TOMAHAWK3(unit)) {
    755         return bcm_tomahawk3_l2_addr_delete(unit, mac, vid);
    756     }
    757 #endif /* BCM_TOMAHAWK3_SUPPORT  */
    758 
    759     L2_INIT(unit);
    760 
    761 #if defined(BCM_TRIUMPH3_SUPPORT)
    762     if (soc_feature(unit, soc_feature_ism_memory)) {
    763         return bcm_tr3_l2_addr_delete(unit, mac, vid);
    764     }
    765 #endif /* BCM_TRIUMPH3_SUPPORT */    
    766 
    767     return mbcm_driver[unit]->mbcm_l2_addr_delete(unit, mac, vid);
    768 }
    769 
    770 /*
    771  * Function:
    772  *	bcm_esw_l2_addr_delete_by_port
    773  * Description:
    774  *	Delete L2 addresses associated with a destination module/port.
    775  * Parameters:
    776  *	unit  - device unit
    777  *	mod   - module id (or -1 for local unit)
    778  *	port  - port
    779  *	flags - BCM_L2_DELETE_XXX
    780  * Returns:
    781  *	BCM_E_XXX
    782  * Notes:
    783  *	Static entries are removed only if BCM_L2_DELETE_STATIC flag is used.
    784  *	L2 aging and learning are disabled during this operation.
    785  */
    786 
    787 int
    788 bcm_esw_l2_addr_delete_by_port(int unit,
    789                                bcm_module_t mod, bcm_port_t port,
    790                                uint32 flags)
    791 {
    792     bcm_l2_addr_t   match_addr;
    793     uint32          repl_flags;
    794     uint32          int_flags = 0;
    795 #if defined(BCM_KATANA2_SUPPORT) || defined(BCM_HGPROXY_COE_SUPPORT)
    796     int             id = -1;
    797     bcm_port_t      _port = -1;
    798     bcm_trunk_t     _trunk = -1;
    799     bcm_module_t    _modid = -1;
    800 #endif
    801 
    802 #if defined(BCM_TOMAHAWK3_SUPPORT)
    803     /* Added to handle SDK functions calling esw version,
    804      * instead of Tomahawk3's version
    805      */
    806     if (SOC_IS_TOMAHAWK3(unit)) {
    807         return bcm_tomahawk3_l2_addr_delete_by_port(unit, mod, port, flags);
    808     }
    809 #endif /* BCM_TOMAHAWK3_SUPPORT  */
    810 
    811     L2_INIT(unit);
    812 
    813 #if defined(BCM_TRIUMPH3_SUPPORT)
    814     if (soc_feature(unit, soc_feature_ism_memory)) {
    815         return bcm_tr3_l2_addr_delete_by_port(unit, mod, port, flags);
    816     }
    817 #endif /* BCM_TRIUMPH3_SUPPORT */    
    818 
    819     sal_memset(&match_addr, 0, sizeof(bcm_l2_addr_t));
    820     if (port == -1) {
    821         match_addr.modid = mod;
    822         match_addr.port  = -1;
    823         int_flags = _BCM_L2_REPLACE_IGNORE_PORTID;
    824     } else if (!BCM_GPORT_IS_SET(port) && mod == -1) {
    825 #ifdef BCM_KATANA2_SUPPORT
    826         if ((soc_feature(unit, soc_feature_linkphy_coe) &&
    827             BCM_PBMP_MEMBER (SOC_INFO(unit).linkphy_pp_port_pbm, port)) ||
    828             (soc_feature(unit, soc_feature_subtag_coe) &&
    829             BCM_PBMP_MEMBER (SOC_INFO(unit).subtag_pp_port_pbm, port))) {
    830                 return BCM_E_PORT;
    831         } else
    832 #endif
    833         if (!SOC_PORT_VALID(unit, port)) {
    834             return BCM_E_PORT;
    835         }
    836         BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &match_addr.modid));
    837     } else {
    838 
    839 #if defined(BCM_HGPROXY_COE_SUPPORT)
    840         if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
    841             BCM_GPORT_IS_SET(port) &&
    842             _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port)) {
    843                 BCM_IF_ERROR_RETURN(
    844                     _bcm_esw_gport_resolve(unit, port, &_modid, &_port, 
    845                                            &_trunk, &id));
    846                 match_addr.modid = _modid;
    847                 port = _port;
    848         } else 
    849 #endif
    850 #if defined(BCM_KATANA2_SUPPORT)
    851         if (_BCM_KT2_GPORT_IS_LINKPHY_OR_SUBTAG_SUBPORT_GPORT(unit, port)) {
    852             BCM_IF_ERROR_RETURN(
    853                 _bcm_esw_gport_resolve(unit, port, &_modid, &_port, 
    854                                        &_trunk, &id));
    855             match_addr.modid = _modid;
    856             port = _port;
    857         } else
    858 #endif
    859         {
    860             match_addr.modid = mod;
    861         }
    862     }
    863     match_addr.port = port;
    864 
    865     BCM_IF_ERROR_RETURN
    866         (_bcm_esw_delete_replace_flags_convert(unit, flags, &repl_flags));
    867     repl_flags |= BCM_L2_REPLACE_MATCH_DEST;
    868     return _bcm_esw_l2_replace(unit, repl_flags, int_flags, &match_addr, 0, 0, 0,
    869                                NULL, NULL);
    870 }
    871 
    872 /*
    873  * Function:
    874  *	bcm_esw_l2_addr_delete_by_mac
    875  * Description:
    876  *	Delete L2 entries associated with a MAC address.
    877  * Parameters:
    878  *	unit  - device unit
    879  *	mac   - MAC address
    880  *	flags - BCM_L2_DELETE_XXX
    881  * Returns:
    882  *	BCM_E_XXX
    883  * Notes:
    884  *	Static entries are removed only if BCM_L2_DELETE_STATIC flag is used.
    885  *	L2 aging and learning are disabled during this operation.
    886  */
    887 int
    888 bcm_esw_l2_addr_delete_by_mac(int unit, bcm_mac_t mac, uint32 flags)
    889 {
    890     bcm_l2_addr_t   match_addr;
    891     uint32          repl_flags;
    892 
    893 #if defined(BCM_TOMAHAWK3_SUPPORT)
    894     /* Added to handle SDK functions calling esw version,
    895      * instead of Tomahawk3's version
    896      */
    897     if (SOC_IS_TOMAHAWK3(unit)) {
    898         return bcm_tomahawk3_l2_addr_delete_by_mac(unit, mac, flags);
    899     }
    900 #endif /* BCM_TOMAHAWK3_SUPPORT  */
    901 
    902     L2_INIT(unit);
    903 
    904 #if defined(BCM_TRIUMPH3_SUPPORT)
    905     if (soc_feature(unit, soc_feature_ism_memory)) {
    906         return bcm_tr3_l2_addr_delete_by_mac(unit, mac, flags);
    907     }
    908 #endif /* BCM_TRIUMPH3_SUPPORT */    
    909 
    910     sal_memset(&match_addr, 0, sizeof(bcm_l2_addr_t));
    911     sal_memcpy(match_addr.mac, mac, sizeof(bcm_mac_t));    
    912     BCM_IF_ERROR_RETURN
    913         (_bcm_esw_delete_replace_flags_convert(unit, flags, &repl_flags));
    914     /* Traverse l2 entry contains MAC address field by key type. */
    915     /* Currently, L2 Bridge and VFI are suported. */
    916     repl_flags |= BCM_L2_REPLACE_MATCH_MAC | BCM_L2_REPLACE_VPN_TYPE;
    917     BCM_IF_ERROR_RETURN
    918         (_bcm_esw_l2_replace(unit, repl_flags, 0, &match_addr, 0, 0, 0, NULL, NULL));
    919     repl_flags &= ~BCM_L2_REPLACE_VPN_TYPE;
    920     return _bcm_esw_l2_replace(unit, repl_flags, 0, &match_addr, 0, 0, 0,
    921                                NULL, NULL);
    922 }
    923 
    924 /*
    925  * Function:
    926  *	bcm_esw_l2_addr_delete_by_vlan
    927  * Description:
    928  *	Delete L2 entries associated with a VLAN.
    929  * Parameters:
    930  *	unit  - device unit
    931  *	vid   - VLAN id
    932  *	flags - BCM_L2_DELETE_XXX
    933  * Returns:
    934  *	BCM_E_XXX
    935  * Notes:
    936  *	Static entries are removed only if BCM_L2_DELETE_STATIC flag is used.
    937  *	L2 aging and learning are disabled during this operation.
    938  */
    939 int
    940 bcm_esw_l2_addr_delete_by_vlan(int unit, bcm_vlan_t vid, uint32 flags)
    941 {
    942     bcm_l2_addr_t   match_addr;
    943     uint32          repl_flags;
    944 
    945 #if defined(BCM_TOMAHAWK3_SUPPORT)
    946     /* Added to handle SDK functions calling esw version,
    947      * instead of Tomahawk3's version
    948      */
    949     if (SOC_IS_TOMAHAWK3(unit)) {
    950         return bcm_tomahawk3_l2_addr_delete_by_vlan(unit, vid, flags);
    951     }
    952 #endif /* BCM_TOMAHAWK3_SUPPORT  */
    953 
    954     L2_INIT(unit);
    955 
    956 #if defined(BCM_TRIUMPH3_SUPPORT)
    957     if (soc_feature(unit, soc_feature_ism_memory)) {
    958         return bcm_tr3_l2_addr_delete_by_vlan(unit, vid, flags);
    959     }
    960 #endif /* BCM_TRIUMPH3_SUPPORT */    
    961 
    962     sal_memset(&match_addr, 0, sizeof(bcm_l2_addr_t));
    963     match_addr.vid = vid;
    964     BCM_IF_ERROR_RETURN
    965         (_bcm_esw_delete_replace_flags_convert(unit, flags, &repl_flags));
    966     repl_flags |= BCM_L2_REPLACE_MATCH_VLAN;
    967     return _bcm_esw_l2_replace(unit, repl_flags, 0, &match_addr, 0, 0, 0,
    968                                NULL, NULL);
    969 }
    970 
    971 /*
    972  * Function:
    973  *	bcm_esw_l2_addr_delete_by_trunk
    974  * Description:
    975  *	Delete L2 entries associated with a trunk.
    976  * Parameters:
    977  *	unit  - device unit
    978  *	tid   - trunk id
    979  *	flags - BCM_L2_DELETE_XXX
    980  * Returns:
    981  *	BCM_E_XXX
    982  * Notes:
    983  *	Static entries are removed only if BCM_L2_DELETE_STATIC flag is used.
    984  *	L2 aging and learning are disabled during this operation.
    985  */
    986 int
    987 bcm_esw_l2_addr_delete_by_trunk(int unit, bcm_trunk_t tid, uint32 flags)
    988 {
    989     bcm_l2_addr_t   match_addr;
    990     uint32          repl_flags;
    991 
    992 #if defined(BCM_TOMAHAWK3_SUPPORT)
    993     /* Added to handle SDK functions calling esw version,
    994      * instead of Tomahawk3's version
    995      */
    996     if (SOC_IS_TOMAHAWK3(unit)) {
    997         return bcm_tomahawk3_l2_addr_delete_by_trunk(unit, tid, flags);
    998     }
    999 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   1000 
   1001     L2_INIT(unit);
   1002 
   1003 #if defined(BCM_TRIUMPH3_SUPPORT)
   1004     if (soc_feature(unit, soc_feature_ism_memory)) {
   1005         return bcm_tr3_l2_addr_delete_by_trunk(unit, tid, flags);
   1006     }
   1007 #endif /* BCM_TRIUMPH3_SUPPORT */    
   1008 
   1009     sal_memset(&match_addr, 0, sizeof(bcm_l2_addr_t));
   1010     match_addr.tgid = tid;
   1011     match_addr.flags = BCM_L2_TRUNK_MEMBER;
   1012     BCM_IF_ERROR_RETURN
   1013         (_bcm_esw_delete_replace_flags_convert(unit, flags, &repl_flags));
   1014     repl_flags |= BCM_L2_REPLACE_MATCH_DEST;
   1015     return _bcm_esw_l2_replace(unit, repl_flags, 0, &match_addr, 0, 0, 0,
   1016                                NULL, NULL);
   1017 }
   1018 
   1019 /*
   1020  * Function:
   1021  *	bcm_esw_l2_addr_delete_by_mac_port
   1022  * Description:
   1023  *	Delete L2 entries associated with a MAC address and
   1024  *	a destination module/port
   1025  * Parameters:
   1026  *	unit  - device unit
   1027  *	mac   - MAC address
   1028  *	mod   - module id
   1029  *	port  - port
   1030  *	flags - BCM_L2_DELETE_XXX
   1031  * Returns:
   1032  *	BCM_E_XXX
   1033  * Notes:
   1034  *	Static entries are removed only if BCM_L2_DELETE_STATIC flag is used.
   1035  *	L2 aging and learning are disabled during this operation.
   1036  */
   1037 int
   1038 bcm_esw_l2_addr_delete_by_mac_port(int unit, bcm_mac_t mac,
   1039                          bcm_module_t mod, bcm_port_t port, uint32 flags)
   1040 {
   1041     bcm_l2_addr_t   match_addr;
   1042     uint32          repl_flags;
   1043 #if (defined(BCM_KATANA2_SUPPORT) || defined(BCM_HGPROXY_COE_SUPPORT))
   1044     int             id = -1;
   1045     bcm_port_t      _port = -1;
   1046     bcm_trunk_t     _trunk = -1;
   1047     bcm_module_t    _modid = -1;
   1048 #endif
   1049 
   1050 #if defined(BCM_TOMAHAWK3_SUPPORT)
   1051     /* Added to handle SDK functions calling esw version,
   1052      * instead of Tomahawk3's version
   1053      */
   1054     if (SOC_IS_TOMAHAWK3(unit)) {
   1055         return bcm_tomahawk3_l2_addr_delete_by_mac_port(unit, mac, mod, port,
   1056                                                         flags);
   1057     }
   1058 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   1059 
   1060     L2_INIT(unit);
   1061 
   1062 #if defined(BCM_TRIUMPH3_SUPPORT)
   1063     if (soc_feature(unit, soc_feature_ism_memory)) {
   1064         return bcm_tr3_l2_addr_delete_by_mac_port(unit, mac,
   1065                                                   mod, port, flags);
   1066     }
   1067 #endif /* BCM_TRIUMPH3_SUPPORT */    
   1068 
   1069     sal_memset(&match_addr, 0, sizeof(bcm_l2_addr_t));
   1070     sal_memcpy(match_addr.mac, mac, sizeof(bcm_mac_t));
   1071     if (!BCM_GPORT_IS_SET(port) && mod == -1) {
   1072 #ifdef BCM_KATANA2_SUPPORT
   1073         if ((soc_feature(unit, soc_feature_linkphy_coe) &&
   1074             BCM_PBMP_MEMBER (SOC_INFO(unit).linkphy_pp_port_pbm, port)) ||
   1075             (soc_feature(unit, soc_feature_subtag_coe) &&
   1076             BCM_PBMP_MEMBER (SOC_INFO(unit).subtag_pp_port_pbm, port))) {
   1077             return BCM_E_PORT;
   1078         } else
   1079 #endif
   1080         if (!SOC_PORT_VALID(unit, port)) {
   1081             return BCM_E_PORT;
   1082         }
   1083         BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &match_addr.modid));
   1084     } else {
   1085 
   1086 #if defined(BCM_HGPROXY_COE_SUPPORT)
   1087         if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
   1088             _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port)) {
   1089                 BCM_IF_ERROR_RETURN(
   1090                     _bcm_esw_gport_resolve(unit, port, &_modid, &_port, 
   1091                                            &_trunk, &id));
   1092                 match_addr.modid = _modid;
   1093                 port = _port;
   1094         } else
   1095 #endif
   1096 
   1097 #if defined(BCM_KATANA2_SUPPORT)
   1098         if (_BCM_KT2_GPORT_IS_LINKPHY_OR_SUBTAG_SUBPORT_GPORT(unit, port)) {
   1099             BCM_IF_ERROR_RETURN(
   1100                 _bcm_esw_gport_resolve(unit, port, &_modid, &_port, 
   1101                                        &_trunk, &id));
   1102             match_addr.modid = _modid;
   1103             port = _port;
   1104         } else
   1105 #endif
   1106         {
   1107             match_addr.modid = mod;
   1108         }
   1109     }
   1110     match_addr.port = port;
   1111     BCM_IF_ERROR_RETURN
   1112         (_bcm_esw_delete_replace_flags_convert(unit, flags, &repl_flags));
   1113     repl_flags |= BCM_L2_REPLACE_MATCH_MAC | BCM_L2_REPLACE_MATCH_DEST;
   1114     return _bcm_esw_l2_replace(unit, repl_flags, 0, &match_addr, 0, 0, 0,
   1115                                NULL, NULL);
   1116 }
   1117 
   1118 /*
   1119  * Function:
   1120  *	bcm_esw_l2_addr_delete_by_vlan_port
   1121  * Description:
   1122  *	Delete L2 entries associated with a VLAN and
   1123  *	a destination module/port
   1124  * Parameters:
   1125  *	unit  - device unit
   1126  *	vid   - VLAN id
   1127  *	mod   - module id
   1128  *	port  - port
   1129  *	flags - BCM_L2_DELETE_XXX
   1130  * Returns:
   1131  *	BCM_E_XXX
   1132  * Notes:
   1133  *	Static entries are removed only if BCM_L2_DELETE_STATIC flag is used.
   1134  *	L2 aging and learning are disabled during this operation.
   1135  */
   1136 int
   1137 bcm_esw_l2_addr_delete_by_vlan_port(int unit, bcm_vlan_t vid,
   1138                            bcm_module_t mod, bcm_port_t port, uint32 flags)
   1139 {
   1140     bcm_l2_addr_t   match_addr;
   1141     uint32          repl_flags;
   1142 #if defined(BCM_KATANA2_SUPPORT) || defined(BCM_HGPROXY_COE_SUPPORT)
   1143     int             id = -1;
   1144     bcm_port_t      _port = -1;
   1145     bcm_trunk_t     _trunk = -1;
   1146     bcm_module_t    _modid = -1;
   1147 #endif
   1148 
   1149 #if defined(BCM_TOMAHAWK3_SUPPORT)
   1150     /* Added to handle SDK functions calling esw version,
   1151      * instead of Tomahawk3's version
   1152      */
   1153     if (SOC_IS_TOMAHAWK3(unit)) {
   1154         return bcm_tomahawk3_l2_addr_delete_by_vlan_port(unit, vid, mod, port,
   1155                                                          flags);
   1156     }
   1157 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   1158 
   1159     L2_INIT(unit);
   1160 
   1161 #if defined(BCM_TRIUMPH3_SUPPORT)
   1162     if (soc_feature(unit, soc_feature_ism_memory)) {
   1163         return bcm_tr3_l2_addr_delete_by_vlan_port(unit, vid,
   1164                                                    mod, port, flags);
   1165     }
   1166 #endif /* BCM_TRIUMPH3_SUPPORT */    
   1167 
   1168     sal_memset(&match_addr, 0, sizeof(bcm_l2_addr_t));
   1169     match_addr.vid = vid;
   1170     if (!BCM_GPORT_IS_SET(port) && mod == -1) {
   1171 #ifdef BCM_KATANA2_SUPPORT
   1172         if ((soc_feature(unit, soc_feature_linkphy_coe) &&
   1173             BCM_PBMP_MEMBER (SOC_INFO(unit).linkphy_pp_port_pbm, port)) ||
   1174             (soc_feature(unit, soc_feature_subtag_coe) &&
   1175             BCM_PBMP_MEMBER (SOC_INFO(unit).subtag_pp_port_pbm, port))) {
   1176             return BCM_E_PORT;
   1177         } else
   1178 #endif
   1179         if (!SOC_PORT_VALID(unit, port)) {
   1180             return BCM_E_PORT;
   1181         }
   1182         BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &match_addr.modid));
   1183     } else {
   1184 
   1185 #if defined(BCM_HGPROXY_COE_SUPPORT)
   1186         if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
   1187             _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port)) {
   1188                 BCM_IF_ERROR_RETURN(
   1189                     _bcm_esw_gport_resolve(unit, port, &_modid, &_port, 
   1190                                            &_trunk, &id));
   1191                 match_addr.modid = _modid;
   1192                 port = _port;
   1193         } else
   1194 #endif
   1195 #if defined(BCM_KATANA2_SUPPORT)
   1196         if (_BCM_KT2_GPORT_IS_LINKPHY_OR_SUBTAG_SUBPORT_GPORT(unit, port)) {
   1197             BCM_IF_ERROR_RETURN(
   1198                 _bcm_esw_gport_resolve(unit, port, &_modid, &_port, 
   1199                                        &_trunk, &id));
   1200             match_addr.modid = _modid;
   1201             port = _port;
   1202         } else
   1203 #endif
   1204         {
   1205             match_addr.modid = mod;
   1206         }
   1207     }
   1208     match_addr.port = port;
   1209     BCM_IF_ERROR_RETURN
   1210         (_bcm_esw_delete_replace_flags_convert(unit, flags, &repl_flags));
   1211     repl_flags |= BCM_L2_REPLACE_MATCH_VLAN | BCM_L2_REPLACE_MATCH_DEST;
   1212     return _bcm_esw_l2_replace(unit, repl_flags, 0, &match_addr, 0, 0, 0,
   1213                                NULL, NULL);
   1214 }
   1215 
   1216 /*
   1217  * Function:
   1218  *	bcm_esw_l2_addr_delete_by_vlan_trunk
   1219  * Description:
   1220  *	Delete L2 entries associated with a VLAN and a
   1221  *      destination trunk.
   1222  * Parameters:
   1223  *	unit  - device unit
   1224  *	vid   - VLAN id
   1225  *	tid   - trunk group id
   1226  *	flags - BCM_L2_DELETE_XXX
   1227  * Returns:
   1228  *	BCM_E_XXX
   1229  * Notes:
   1230  *	Static entries are removed only if BCM_L2_DELETE_STATIC flag is used.
   1231  *	L2 aging and learning are disabled during this operation.
   1232  */
   1233 int
   1234 bcm_esw_l2_addr_delete_by_vlan_trunk(int unit, bcm_vlan_t vid,
   1235                                  bcm_trunk_t tid, uint32 flags)
   1236 {
   1237     bcm_l2_addr_t   match_addr;
   1238     uint32          repl_flags;
   1239 
   1240 #if defined(BCM_TOMAHAWK3_SUPPORT)
   1241     /* Added to handle SDK functions calling esw version,
   1242      * instead of Tomahawk3's version
   1243      */
   1244     if (SOC_IS_TOMAHAWK3(unit)) {
   1245         return bcm_tomahawk3_l2_addr_delete_by_vlan_trunk(unit, vid, tid,
   1246                                                           flags);
   1247     }
   1248 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   1249 
   1250     L2_INIT(unit);
   1251 
   1252 #if defined(BCM_TRIUMPH3_SUPPORT)
   1253     if (soc_feature(unit, soc_feature_ism_memory)) {
   1254         return bcm_tr3_l2_addr_delete_by_vlan_trunk(unit, vid, tid, flags);
   1255     }
   1256 #endif /* BCM_TRIUMPH3_SUPPORT */    
   1257 
   1258     sal_memset(&match_addr, 0, sizeof(bcm_l2_addr_t));
   1259     match_addr.vid = vid;
   1260     match_addr.tgid = tid;
   1261     match_addr.flags = BCM_L2_TRUNK_MEMBER;
   1262     BCM_IF_ERROR_RETURN
   1263         (_bcm_esw_delete_replace_flags_convert(unit, flags, &repl_flags));
   1264     repl_flags |= BCM_L2_REPLACE_MATCH_VLAN | BCM_L2_REPLACE_MATCH_DEST;
   1265     return _bcm_esw_l2_replace(unit, repl_flags, 0, &match_addr, 0, 0, 0,
   1266                                NULL, NULL);
   1267 }
   1268 
   1269 /*
   1270  * Function:
   1271  *	bcm_l2_addr_get
   1272  * Description:
   1273  *	Given a MAC address and VLAN ID, check if the entry is present
   1274  *	in the L2 table, and if so, return all associated information.
   1275  * Parameters:
   1276  *	unit - StrataSwitch PCI device unit number (driver internal).
   1277  *	mac - input MAC address to search
   1278  *	vid - input VLAN ID to search
   1279  *	l2addr - Pointer to bcm_l2_addr_t structure to receive results
   1280  * Returns:
   1281  *	BCM_E_NONE		Success (l2addr filled in)
   1282  *	BCM_E_PARAM		Illegal parameter (NULL pointer)
   1283  *	BCM_E_INTERNAL		Chip access failure
   1284  *	BCM_E_NOT_FOUND	        Address not found (l2addr not filled in)
   1285  */
   1286 
   1287 int
   1288 bcm_esw_l2_addr_get(int unit, sal_mac_addr_t mac,
   1289 		bcm_vlan_t vid, bcm_l2_addr_t *l2addr)
   1290 {
   1291 #if defined(BCM_TOMAHAWK3_SUPPORT)
   1292     /* Added to handle SDK functions calling esw version,
   1293      * instead of Tomahawk3's version
   1294      */
   1295     if (SOC_IS_TOMAHAWK3(unit)) {
   1296         return bcm_tomahawk3_l2_addr_get(unit, mac, vid, l2addr);
   1297     }
   1298 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   1299 
   1300     L2_INIT(unit);
   1301 
   1302 #if defined(BCM_TRIUMPH3_SUPPORT)
   1303     if (soc_feature(unit, soc_feature_ism_memory)) {
   1304         return bcm_tr3_l2_addr_get(unit, mac, vid, l2addr);
   1305     }
   1306 #endif /* BCM_TRIUMPH3_SUPPORT */    
   1307 
   1308     SOC_IF_ERROR_RETURN(
   1309         mbcm_driver[unit]->mbcm_l2_addr_get(unit, mac, vid, l2addr));
   1310 
   1311     return BCM_E_NONE;
   1312 }
   1313 
   1314 /****************************************************************************
   1315  *
   1316  * L2X Message Registration
   1317  */
   1318 
   1319 #define L2_CB_MAX		3
   1320 
   1321 typedef struct l2x_cb_entry_s {
   1322     bcm_l2_addr_callback_t	fn;
   1323     void			*fn_data;
   1324 } l2_cb_entry_t;
   1325 
   1326 #define _BCM_L2X_THREAD_STOP      (1 << 0)
   1327 typedef struct l2_data_s {
   1328     l2_cb_entry_t		cb[L2_CB_MAX];
   1329     int				cb_count;
   1330     int                 flags;
   1331     sal_mutex_t                 l2_mutex;
   1332 } l2_data_t;
   1333 
   1334 static l2_data_t l2_data[SOC_MAX_NUM_DEVICES];
   1335 
   1336 
   1337 #define L2_LOCK(unit) \
   1338     sal_mutex_take(l2_data[unit].l2_mutex, sal_mutex_FOREVER)
   1339 
   1340 #define L2_UNLOCK(unit) sal_mutex_give(l2_data[unit].l2_mutex)
   1341 
   1342 #define L2_MUTEX(unit) if (l2_data[unit].l2_mutex == NULL &&                 \
   1343         (l2_data[unit].l2_mutex = sal_mutex_create("bcm_l2_lock")) == NULL)  \
   1344             return BCM_E_MEMORY
   1345 
   1346 /*
   1347  * Function:
   1348  *      bcm_esw_l2_port_native
   1349  * Purpose:
   1350  *      Determine if the given port is "native" from the point
   1351  *      of view of L2.
   1352  * Parameters:
   1353  *      unit       - The unit
   1354  *      modid      - Module ID of L2 entry being queried
   1355  *      port       - Module port of L2 entry being queried
   1356  * Returns:
   1357  *      TRUE (> 0) if (modid, port) is front panel/CPU port for unit.
   1358  *      FALSE (0) otherwise.
   1359  *      < 0 on error.
   1360  *
   1361  *      Native means front panel, but also includes the CPU port.
   1362  *      HG ports are always excluded as are ports marked as internal or
   1363  *      external stacking
   1364  */
   1365 
   1366 int
   1367 bcm_esw_l2_port_native(int unit, int modid, int port)
   1368 {
   1369     int unit_modid;
   1370     int unit_port;  /* In case unit supports multiple module IDs */
   1371     bcm_trunk_t     tgid;
   1372     int             id, isLocal;
   1373 
   1374 #if defined(BCM_TOMAHAWK3_SUPPORT)
   1375     /* Added to handle SDK functions calling esw version,
   1376      * instead of Tomahawk3's version
   1377      */
   1378     if (SOC_IS_TOMAHAWK3(unit)) {
   1379         return bcm_tomahawk3_l2_port_native(unit, modid, port);
   1380     }
   1381 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   1382 
   1383     L2_INIT(unit);
   1384 
   1385 #if defined(BCM_TRIUMPH3_SUPPORT)
   1386     if (soc_feature(unit, soc_feature_ism_memory)) {
   1387         return bcm_tr3_l2_port_native(unit, modid, port);
   1388     }
   1389 #endif /* BCM_TRIUMPH3_SUPPORT */    
   1390 
   1391     if (BCM_GPORT_IS_SET(port)) {
   1392         BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, port, &modid,
   1393             &port, &tgid, &id));
   1394 
   1395         if (-1 != id || BCM_TRUNK_INVALID != tgid) {
   1396             return FALSE;
   1397         }
   1398     }
   1399 
   1400     BCM_IF_ERROR_RETURN(_bcm_esw_modid_is_local(unit, modid, &isLocal));
   1401     if (isLocal != TRUE) {
   1402         return FALSE;
   1403     }
   1404 
   1405     BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &unit_modid));
   1406     if (unit_modid != modid) {
   1407         unit_port = port + 32; 
   1408     } else {
   1409         unit_port = port;
   1410     }
   1411 
   1412     if (IS_ST_PORT(unit, unit_port)) {
   1413         return FALSE;
   1414     } 
   1415 
   1416     return TRUE;
   1417 }
   1418 
   1419 
   1420 /****************************************************************************
   1421  *
   1422  * L2 Callbacks Registration
   1423  */
   1424 static bcm_l2_addr_callback_t _bcm_l2_cbs[SOC_MAX_NUM_DEVICES];
   1425 static void *_bcm_l2_cb_data[SOC_MAX_NUM_DEVICES];
   1426 
   1427 #if defined(BCM_TSN_SUPPORT)
   1428 /*
   1429  * Function:
   1430  *    bcmi_l2_addr_tsn_sr_flowset_ref_update
   1431  * Purpose:
   1432  *    Update reference count for the specified TSN/SR flowset
   1433  *    associated it to a L2 addition/deletion
   1434  * Parameters:
   1435  *    unit      - unit number.
   1436  *    entry_del - entry deleted from the HW L2_ENTRY memory
   1437  *    entry_add - entry added into the HW L2_ENTRY memory
   1438  * Returns:
   1439  *    BCM_E_NONE
   1440  */
   1441 STATIC int
   1442 bcmi_l2_addr_tsn_sr_flowset_ref_update(
   1443     int unit,
   1444     uint32 *entry_del,
   1445     uint32 *entry_add)
   1446 {
   1447     int rv = BCM_E_NONE;
   1448     bcm_l2_addr_t l2addr_del, l2addr_add;
   1449 #if defined(BCM_TSN_SR_SUPPORT)
   1450     int mp_index = 0; /* TSN SR MAC Proxy profile index */
   1451     bcm_pbmp_t mp_pbmp;
   1452 #endif /* BCM_TSN_SR_SUPPORT */
   1453 
   1454     L2_INIT(unit);
   1455 
   1456     /* Input parameters check */
   1457     if ((entry_del == NULL) && (entry_add == NULL)) {
   1458         return BCM_E_NONE;
   1459     }
   1460 
   1461     if (entry_del != NULL) {
   1462         /* Parse L2X entry into L2_Addr structure */
   1463         (void)_bcm_esw_l2_from_l2x(unit, 0, &l2addr_del, entry_del);
   1464     }
   1465     if (entry_add != NULL) {
   1466         /* Parse L2X entry into L2_Addr structure */
   1467         (void)_bcm_esw_l2_from_l2x(unit, 0, &l2addr_add, entry_add);
   1468     }
   1469 
   1470     if (soc_feature(unit, soc_feature_tsn)) {
   1471         if ((entry_del != NULL) && (l2addr_del.tsn_flowset != 0)) {
   1472             /* decrease TSN flowset ref_cnt */
   1473             rv = bcmi_esw_tsn_flowset_ref_dec(unit, l2addr_del.tsn_flowset);
   1474             if (BCM_FAILURE(rv)) {
   1475                 LOG_WARN(BSL_LS_BCM_ARL,
   1476                          (BSL_META_U(unit,
   1477                                      "bcmi_l2_addr_tsn_sr_flowset_ref_update:"
   1478                                      " can't decrease TSN flowset ref_cnt!!!"
   1479                                      "\n")));
   1480                 return BCM_E_NONE;
   1481             }
   1482         }
   1483         if ((entry_add != NULL) && (l2addr_add.tsn_flowset != 0)) {
   1484             /* increase TSN flowset ref_cnt */
   1485             rv = bcmi_esw_tsn_flowset_ref_inc(unit, l2addr_add.tsn_flowset);
   1486             if (BCM_FAILURE(rv)) {
   1487                 LOG_WARN(BSL_LS_BCM_ARL,
   1488                          (BSL_META_U(unit,
   1489                                      "bcmi_l2_addr_tsn_sr_flowset_ref_update:"
   1490                                      " can't increase TSN flowset ref_cnt!!!"
   1491                                      "\n")));
   1492                 return BCM_E_NONE;
   1493             }
   1494         }
   1495     }
   1496 
   1497 #if defined(BCM_TSN_SR_SUPPORT)
   1498     if (soc_feature(unit, soc_feature_tsn_sr)) {
   1499         if ((entry_del != NULL) && (l2addr_del.sr_flowset != 0)) {
   1500             /* decrease TSN SR flowset ref_cnt */
   1501             rv = bcmi_esw_tsn_sr_flowset_ref_dec(unit, l2addr_del.sr_flowset);
   1502             if (BCM_FAILURE(rv)) {
   1503                 LOG_WARN(BSL_LS_BCM_ARL,
   1504                          (BSL_META_U(unit,
   1505                                      "bcmi_l2_addr_tsn_sr_flowset_ref_update:"
   1506                                      " can't decrease SR flowset ref_cnt!!!"
   1507                                      "\n")));
   1508                 return BCM_E_NONE;
   1509             }
   1510             /* decrease TSN SR MAC Proxy ref_cnt */
   1511             if (!BCM_PBMP_IS_NULL(l2addr_del.sa_source_filter_pbmp)) {
   1512                 mp_index = soc_L2Xm_field32_get(unit, entry_del,
   1513                                                 SR_MAC_PROXY_PROFILE_PTRf);
   1514                 if (mp_index != 0) {
   1515                     rv = bcmi_esw_tsn_sr_mac_proxy_delete(unit, mp_index);
   1516                     if (BCM_FAILURE(rv)) {
   1517                         LOG_WARN(BSL_LS_BCM_ARL,
   1518                                  (BSL_META_U(unit,
   1519                                              "bcmi_esw_tsn_sr_mac_proxy_delete"
   1520                                              ": can't delete SR MAC Proxy!!!"
   1521                                              "\n")));
   1522                         return BCM_E_NONE;
   1523                     }
   1524                 }
   1525             }
   1526         }
   1527         if ((entry_add != NULL) && (l2addr_add.sr_flowset != 0)) {
   1528             /* increase TSN SR flowset ref_cnt */
   1529             rv = bcmi_esw_tsn_sr_flowset_ref_inc(unit, l2addr_add.sr_flowset);
   1530             if (BCM_FAILURE(rv)) {
   1531                 LOG_WARN(BSL_LS_BCM_ARL,
   1532                          (BSL_META_U(unit,
   1533                                      "bcmi_l2_addr_tsn_sr_flowset_ref_update:"
   1534                                      " can't increase SR flowset ref_cnt!!!"
   1535                                      "\n")));
   1536                 return BCM_E_NONE;
   1537             }
   1538             /* increase TSN SR MAC Proxy ref_cnt */
   1539             if (!BCM_PBMP_IS_NULL(l2addr_add.sa_source_filter_pbmp)) {
   1540                 /* The value should be inverted between SW and HW view */
   1541                 BCM_PBMP_NEGATE(mp_pbmp, l2addr_add.sa_source_filter_pbmp);
   1542                 BCM_PBMP_AND(mp_pbmp, PBMP_ALL(unit));
   1543                 rv = bcmi_esw_tsn_sr_mac_proxy_insert(unit, mp_pbmp,
   1544                                                       &mp_index);
   1545                 if (BCM_FAILURE(rv)) {
   1546                     LOG_WARN(BSL_LS_BCM_ARL,
   1547                              (BSL_META_U(unit,
   1548                                          "bcmi_esw_tsn_sr_mac_proxy_insert"
   1549                                          ": can't insert SR MAC Proxy!!!"
   1550                                          "\n")));
   1551                     return BCM_E_NONE;
   1552                 }
   1553             }
   1554         }
   1555     }
   1556 #endif /* BCM_TSN_SR_SUPPORT */
   1557 
   1558     return rv;
   1559 }
   1560 #endif /* BCM_TSN_SUPPORT */
   1561 
   1562 /*
   1563  * Function:
   1564  *      _bcm_l2_register_callback
   1565  * Description:
   1566  *      Call back to handle bcm_l2_addr_register clients.
   1567  * Parameters:
   1568  *      unit - StrataSwitch unit number.
   1569  *      entry_del - Entry to be deleted or updated, NULL if none.
   1570  *      entry_add - Entry to be inserted or updated, NULL if none.
   1571  *      fn_data - unused
   1572  * Notes:
   1573  *      Only one callback per unit to the bcm layer is supported here.
   1574  *      Multiple bcm client callbacks per unit are supported in the bcm layer.
   1575  */
   1576 void
   1577 _bcm_l2_register_callback(int unit,
   1578                           int pflags,
   1579                           l2x_entry_t *entry_del,
   1580                           l2x_entry_t *entry_add,
   1581                           void *fn_data)
   1582 {
   1583     bcm_l2_addr_t l2addr_del, l2addr_add;
   1584     _bcm_l2_match_ctrl_t *match_ctrl;
   1585     l2x_entry_t *l2x_entry_buf;
   1586     uint32 flags = 0;
   1587     int buf_index, entry_index;
   1588     int l2_callback_event;
   1589 
   1590     if (_l2_init[unit] == 0) {
   1591         return;
   1592     }
   1593 
   1594 #if defined(BCM_TSN_SUPPORT)
   1595     if (pflags & SOC_L2X_ENTRY_TSN_SR_FLOWSET_REF_CNT) {
   1596         if (soc_feature(unit, soc_feature_tsn)) {
   1597             (void)bcmi_l2_addr_tsn_sr_flowset_ref_update
   1598                       (unit, (uint32 *)entry_del, (uint32 *)entry_add);
   1599         }
   1600     } else
   1601 #endif /* BCM_TSN_SUPPORT */
   1602     if (pflags & (SOC_L2X_ENTRY_DUMMY | SOC_L2X_ENTRY_NO_ACTION)) {
   1603         /* pass l2addr_add info match */
   1604         match_ctrl = _bcm_l2_match_ctrl[unit];
   1605         buf_index = match_ctrl->entry_wr_idx / _BCM_L2_MATCH_ENTRY_BUF_SIZE;
   1606         entry_index = match_ctrl->entry_wr_idx % _BCM_L2_MATCH_ENTRY_BUF_SIZE;
   1607         if (entry_index == 0) {
   1608             if (buf_index >= _BCM_L2_MATCH_ENTRY_BUF_COUNT) {
   1609                 return;
   1610             }
   1611             match_ctrl->l2x_entry_buf[buf_index] =
   1612                 sal_alloc(sizeof(l2x_entry_t) * _BCM_L2_MATCH_ENTRY_BUF_SIZE,
   1613                           "l2_matched_traverse");
   1614             if (match_ctrl->l2x_entry_buf[buf_index] == NULL) {
   1615                 return;
   1616             }
   1617         }
   1618         l2x_entry_buf = match_ctrl->l2x_entry_buf[buf_index];
   1619 
   1620         if (pflags & SOC_L2X_ENTRY_NO_ACTION) {
   1621             l2x_entry_buf[entry_index] = *entry_add;
   1622         } else {
   1623             sal_memcpy(&l2x_entry_buf[entry_index],
   1624                        soc_mem_entry_null(unit, L2Xm), sizeof(l2x_entry_t));
   1625         }
   1626         match_ctrl->entry_wr_idx++;
   1627         sal_sem_give(match_ctrl->sem);
   1628         sal_thread_yield();
   1629     } else if (_bcm_l2_cbs[unit] != NULL) {
   1630         flags = 0; /* Common flags: Move, From/to native */
   1631 
   1632         sal_memset(&l2addr_del, 0, sizeof(bcm_l2_addr_t));
   1633         sal_memset(&l2addr_add, 0, sizeof(bcm_l2_addr_t));
   1634 
   1635         /* First, set up the entries:  decode HW entries and set flags */
   1636         if (entry_del != NULL) {
   1637             (void)_bcm_esw_l2_from_l2x(unit, 0, &l2addr_del, (uint32 *)entry_del);
   1638         }
   1639         if (entry_add != NULL) {
   1640             (void)_bcm_esw_l2_from_l2x(unit, 0, &l2addr_add, (uint32 *)entry_add);
   1641         }
   1642 
   1643         if ((entry_del != NULL) && (entry_add != NULL)) { /* It's a move */
   1644             flags |= BCM_L2_MOVE;
   1645             if (SOC_USE_GPORT(unit)) {
   1646                 if (l2addr_del.port != l2addr_add.port) {
   1647                     flags |= BCM_L2_MOVE_PORT;
   1648                 }
   1649             } else {
   1650                 if (l2addr_del.modid != l2addr_add.modid ||
   1651                     l2addr_del.tgid != l2addr_add.tgid ||
   1652                     l2addr_del.port != l2addr_add.port) {
   1653                     flags |= BCM_L2_MOVE_PORT;
   1654                 }
   1655             }
   1656             if (!(l2addr_del.flags & BCM_L2_TRUNK_MEMBER)) {
   1657                 if (bcm_esw_l2_port_native(unit, l2addr_del.modid,
   1658                                            l2addr_del.port) > 0) {
   1659                     flags |= BCM_L2_FROM_NATIVE;
   1660                     l2addr_del.flags |= BCM_L2_NATIVE;
   1661                 }
   1662             }
   1663             if (!(l2addr_add.flags & BCM_L2_TRUNK_MEMBER)) {
   1664                 if (bcm_esw_l2_port_native(unit, l2addr_add.modid,
   1665                                            l2addr_add.port) > 0) {
   1666                     flags |= BCM_L2_TO_NATIVE;
   1667                     l2addr_add.flags |= BCM_L2_NATIVE;
   1668                 }
   1669             }
   1670             l2addr_del.flags |= flags;
   1671             l2addr_add.flags |= flags;
   1672         } else if (entry_del != NULL) { /* Age out or simple delete */
   1673             if (!(l2addr_del.flags & BCM_L2_TRUNK_MEMBER)) {
   1674                 if (bcm_esw_l2_port_native(unit, l2addr_del.modid,
   1675                                             l2addr_del.port) > 0) {
   1676                     l2addr_del.flags |= BCM_L2_NATIVE;
   1677                 }
   1678             }
   1679         } else if (entry_add != NULL) { /* Insert or learn */
   1680             if (!(l2addr_add.flags & BCM_L2_TRUNK_MEMBER)) {
   1681                 if (bcm_esw_l2_port_native(unit, l2addr_add.modid,
   1682                                            l2addr_add.port) > 0) {
   1683                     l2addr_add.flags |= BCM_L2_NATIVE;
   1684                 }
   1685             }
   1686         }
   1687 
   1688 #ifdef BCM_TRIDENT_SUPPORT
   1689         /* Filter out the erroneous station moves. */
   1690         if (SOC_IS_TRIDENT(unit) &&
   1691             !(sal_memcmp(&l2addr_del, &l2addr_add, sizeof(bcm_l2_addr_t)))) {
   1692             return;
   1693         }
   1694 #endif /* BCM_TRIDENT_SUPPORT */
   1695 
   1696 
   1697         /* The entries are now set up.  Make the callbacks */
   1698         if (entry_del != NULL) {
   1699             if (pflags & SOC_L2X_ENTRY_DELETE) {
   1700                 l2_callback_event = BCM_L2_CALLBACK_DELETE;
   1701             } else if (pflags & SOC_L2X_ENTRY_AGE) {
   1702                 l2_callback_event = BCM_L2_CALLBACK_AGE_EVENT;
   1703             } else {
   1704                 l2_callback_event = BCM_L2_CALLBACK_DELETE;
   1705             }
   1706             _bcm_l2_cbs[unit](unit, &l2addr_del,
   1707                               l2_callback_event,
   1708                               _bcm_l2_cb_data[unit]);
   1709         }
   1710 
   1711         if (pflags & SOC_L2X_ENTRY_OVERFLOW) {
   1712             l2addr_add.flags |= BCM_L2_ENTRY_OVERFLOW;
   1713         }
   1714 
   1715         if (entry_add != NULL) {
   1716             if ((flags & BCM_L2_MOVE) &&
   1717                 ((pflags & (SOC_L2X_ENTRY_INSERT | SOC_L2X_ENTRY_LEARN)))) {
   1718                 l2_callback_event = BCM_L2_CALLBACK_MOVE_EVENT;
   1719             } else if (pflags & SOC_L2X_ENTRY_INSERT) {
   1720                 l2_callback_event = BCM_L2_CALLBACK_ADD;
   1721             } else if (pflags & SOC_L2X_ENTRY_LEARN) {
   1722                 l2_callback_event = BCM_L2_CALLBACK_LEARN_EVENT;
   1723             } else {
   1724                 l2_callback_event = BCM_L2_CALLBACK_ADD;
   1725             }
   1726             _bcm_l2_cbs[unit](unit, &l2addr_add,
   1727                               l2_callback_event,
   1728                               _bcm_l2_cb_data[unit]);
   1729         }
   1730     }
   1731 }
   1732 
   1733 
   1734 
   1735 /*
   1736  * Function:
   1737  * 	_bcm_l2_addr_callback
   1738  * Description:
   1739  *	Callback used with chip addr registration functions.
   1740  *	This callback calls all the top level client callbacks.
   1741  * Parameters:
   1742  *	unit - StrataSwitch PCI device unit number (driver internal).
   1743  *	l2addr
   1744  *	insert
   1745  *	userdata
   1746  * Returns:
   1747  */
   1748 static void
   1749 _bcm_l2_addr_callback(int unit,
   1750 		      bcm_l2_addr_t *l2addr,
   1751 		      int insert,
   1752 		      void *userdata)
   1753 {
   1754     l2_data_t		*ad = &l2_data[unit];
   1755     int i;
   1756 
   1757     if (ad->l2_mutex == NULL) {
   1758         return;
   1759     }
   1760 
   1761     L2_LOCK(unit);
   1762     for(i = 0; i < L2_CB_MAX; i++) {
   1763 	if(ad->cb[i].fn) {
   1764 	    ad->cb[i].fn(unit, l2addr, insert, ad->cb[i].fn_data);
   1765 	}
   1766     }
   1767     L2_UNLOCK(unit);
   1768 }
   1769 
   1770 
   1771 /*
   1772  * Function:
   1773  *	bcm_esw_l2_addr_register
   1774  * Description:
   1775  *	Register a callback routine that will be called whenever
   1776  *	an entry is inserted into or deleted from the L2 address table.
   1777  * Parameters:
   1778  *	unit - StrataSwitch PCI device unit number (driver internal).
   1779  *	fn - Callback function of type bcm_l2_addr_callback_t.
   1780  *	fn_data - Arbitrary value passed to callback along with messages
   1781  * Returns:
   1782  *	BCM_E_NONE		Success, handle valid
   1783  *	BCM_E_MEMORY		Out of memory
   1784  *	BCM_E_INTERNAL		Chip access failure
   1785  */
   1786 
   1787 int
   1788 bcm_esw_l2_addr_register(int unit,
   1789                          bcm_l2_addr_callback_t fn,
   1790                          void *fn_data)
   1791 {
   1792     l2_data_t		*ad = &l2_data[unit];
   1793     int i;
   1794 #if defined(BCM_XGS_SWITCH_SUPPORT)
   1795     int rv = BCM_E_NONE;
   1796     int usec;
   1797 #endif /* BCM_XGS_SWITCH_SUPPORT */
   1798 
   1799     if (!SOC_IS_XGS_SWITCH(unit)) {
   1800         return BCM_E_UNAVAIL;
   1801     }
   1802 
   1803 #if defined(BCM_TOMAHAWK3_SUPPORT)
   1804     /* Added to handle SDK functions calling esw version,
   1805      * instead of Tomahawk3's version
   1806      */
   1807     if (SOC_IS_TOMAHAWK3(unit)) {
   1808         return bcm_tomahawk3_l2_addr_register(unit, fn, fn_data);
   1809     }
   1810 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   1811 
   1812     L2_INIT(unit);
   1813 
   1814 #if defined(BCM_TRIUMPH3_SUPPORT)
   1815     if (soc_feature(unit, soc_feature_ism_memory)) {
   1816         return bcm_tr3_l2_addr_register(unit, fn, fn_data);
   1817     }
   1818 #endif /* BCM_TRIUMPH3_SUPPORT */    
   1819 
   1820     _bcm_l2_cbs[unit] = _bcm_l2_addr_callback;
   1821     _bcm_l2_cb_data[unit] = NULL;
   1822 
   1823     L2_MUTEX(unit);
   1824     L2_LOCK(unit);
   1825 #if defined(BCM_XGS_SWITCH_SUPPORT)
   1826     /* Start L2x thread if it isn't running already. */
   1827     if (!soc_l2x_running(unit, NULL, NULL)) {
   1828         usec = (SAL_BOOT_BCMSIM && !SOC_IS_TRIDENT3X(unit)) ? \
   1829                 BCMSIM_L2XMSG_INTERVAL : 3000000;
   1830         usec = soc_property_get(unit, spn_L2XMSG_THREAD_USEC, usec);
   1831         rv = soc_l2x_start(unit, 0, usec);
   1832         if ((BCM_FAILURE(rv)) && (rv != BCM_E_UNAVAIL)) {
   1833             _bcm_l2_cbs[unit] = NULL;
   1834             _bcm_l2_cb_data[unit] = NULL;
   1835             L2_UNLOCK(unit);
   1836             return(rv);
   1837         }
   1838         ad->flags |= _BCM_L2X_THREAD_STOP;
   1839     }
   1840 #endif /* BCM_XGS_SWITCH_SUPPORT */
   1841 
   1842 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_HURRICANE3_SUPPORT)
   1843     if (soc_feature(unit, soc_feature_l2_overflow)) {
   1844 #if defined(BCM_TRIDENT2_SUPPORT)
   1845         if (SOC_IS_TD2_TT2(unit)) {
   1846             rv = soc_td2_l2_overflow_start(unit);
   1847         }
   1848 #endif /* BCM_TRIDENT2_SUPPORT */
   1849 #if defined(BCM_HURRICANE3_SUPPORT)
   1850         if (SOC_IS_HURRICANE3(unit) || SOC_IS_GREYHOUND2(unit)) {
   1851             rv = soc_hr3_l2_overflow_start(unit);
   1852         }
   1853 #endif /* BCM_HURRICANE3_SUPPORT */
   1854         if ((BCM_FAILURE(rv)) && (rv != BCM_E_UNAVAIL)) {
   1855             _bcm_l2_cbs[unit] = NULL;
   1856             _bcm_l2_cb_data[unit] = NULL;
   1857             L2_UNLOCK(unit);
   1858             return(rv);
   1859         }
   1860     }
   1861 #endif
   1862 
   1863     /* See if the function is already registered (with same data) */
   1864     for (i = 0; i < L2_CB_MAX; i++) {
   1865 	if (ad->cb[i].fn == fn && ad->cb[i].fn_data == fn_data) {
   1866             L2_UNLOCK(unit);
   1867             return BCM_E_NONE;
   1868         }
   1869     }
   1870 
   1871     /* Not found; add to list. */
   1872     for (i = 0; i < L2_CB_MAX; i++) {
   1873 	if (ad->cb[i].fn == NULL) {
   1874 	    ad->cb[i].fn = fn;
   1875 	    ad->cb[i].fn_data = fn_data;
   1876 	    ad->cb_count++;
   1877 	    break;
   1878 	}
   1879     }
   1880 
   1881     L2_UNLOCK(unit);
   1882     return i >= L2_CB_MAX ? BCM_E_RESOURCE : BCM_E_NONE;
   1883 }
   1884 
   1885 /*
   1886  * Function:
   1887  *	bcm_esw_l2_addr_unregister
   1888  * Description:
   1889  *	Unregister a previously registered callback routine.
   1890  * Parameters:
   1891  *	unit - StrataSwitch PCI device unit number (driver internal).
   1892  *	fn - Same callback function used to register callback
   1893  *	fn_data - Same arbitrary value used to register callback
   1894  * Returns:
   1895  *	BCM_E_NONE		Success, handle valid
   1896  *	BCM_E_MEMORY		Out of memory
   1897  *	BCM_E_INTERNAL		Chip access failure
   1898  * Notes:
   1899  *	Both callback and userdata must match from original register call.
   1900  */
   1901 
   1902 int
   1903 bcm_esw_l2_addr_unregister(int unit,
   1904 		       bcm_l2_addr_callback_t fn,
   1905 		       void *fn_data)
   1906 {
   1907     l2_data_t		*ad = &l2_data[unit];
   1908     int             rv = BCM_E_NOT_FOUND;
   1909     int			i;
   1910 
   1911     if (!SOC_IS_XGS_SWITCH(unit)) {
   1912         return BCM_E_UNAVAIL;
   1913     }
   1914 
   1915 #if defined(BCM_TOMAHAWK3_SUPPORT)
   1916     /* Added to handle SDK functions calling esw version,
   1917      * instead of Tomahawk3's version
   1918      */
   1919     if (SOC_IS_TOMAHAWK3(unit)) {
   1920         return bcm_tomahawk3_l2_addr_unregister(unit, fn, fn_data);
   1921     }
   1922 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   1923 
   1924 #if defined(BCM_TRIUMPH3_SUPPORT)
   1925     if (soc_feature(unit, soc_feature_ism_memory)) {
   1926         return bcm_tr3_l2_addr_unregister(unit, fn, fn_data);
   1927     }
   1928 #endif /* BCM_TRIUMPH3_SUPPORT */    
   1929 
   1930     L2_INIT(unit);
   1931     L2_MUTEX(unit);
   1932     L2_LOCK(unit);
   1933 
   1934     for (i = 0; i < L2_CB_MAX; i++) {
   1935         if((ad->cb[i].fn == fn) && (ad->cb[i].fn_data == fn_data)) {
   1936             rv = BCM_E_NONE;
   1937             ad->cb[i].fn = NULL;
   1938             ad->cb[i].fn_data = NULL;
   1939             ad->cb_count--;
   1940             if (ad->cb_count == 0) {
   1941                 _bcm_l2_cbs[unit] = NULL;
   1942                 _bcm_l2_cb_data[unit] = NULL;
   1943 
   1944 #if defined(BCM_XGS_SWITCH_SUPPORT)
   1945                 /* Stop l2x thread if callback registration started it. */
   1946                 if (ad->flags & _BCM_L2X_THREAD_STOP) {
   1947                     rv = soc_l2x_stop(unit);
   1948                     ad->flags &= ~_BCM_L2X_THREAD_STOP;
   1949                 }
   1950 #endif /* BCM_XGS_SWITCH_SUPPORT */
   1951             }
   1952         }
   1953     }
   1954 
   1955     L2_UNLOCK(unit);
   1956     return (rv);
   1957 }
   1958 int _bcm_esw_l2_age_timer_set(int unit, int age_seconds, int enabled)
   1959 {
   1960     int			rv;
   1961 #ifdef BCM_XGS_SWITCH_SUPPORT
   1962     int         frozen = 0;
   1963 #endif
   1964     /* Lock ARLm b/c soc_arl_freeze() does read/modify/write of AGE_TIMER */
   1965     SOC_L2X_MEM_LOCK(unit);
   1966 #ifdef BCM_XGS_SWITCH_SUPPORT
   1967     rv = soc_l2x_is_frozen(unit, SOC_L2X_FROZEN, &frozen);
   1968 
   1969     if ((!SOC_IS_TRIUMPH3(unit))&& frozen) {
   1970         soc_age_timer_cache_set(unit, age_seconds, enabled);
   1971         enabled = 0; /* L2x is frozen, so we can't enable aging function */
   1972     } 
   1973 #endif
   1974 
   1975     rv = SOC_FUNCTIONS(unit)->soc_age_timer_set(unit, age_seconds, enabled);
   1976     SOC_L2X_MEM_UNLOCK(unit);
   1977     return rv;
   1978 }
   1979 
   1980 /*
   1981  * Function:
   1982  *	bcm_esw_l2_age_timer_set
   1983  * Description:
   1984  *	Set the age timer for all blocks.
   1985  *	Setting the value to 0 disables the age timer.
   1986  * Parameters:
   1987  *	unit - StrataSwitch PCI device unit number (driver internal).
   1988  *	age_seconds - Age timer value in seconds
   1989  * Returns:
   1990  *	BCM_E_NONE		Success
   1991  *	BCM_E_INTERNAL		Chip access failure
   1992  */
   1993 
   1994 int
   1995 bcm_esw_l2_age_timer_set(int unit, int age_seconds)
   1996 {
   1997     int			max_value;
   1998     int			enabled;
   1999     int			rv;
   2000 
   2001 #if defined(BCM_TOMAHAWK3_SUPPORT)
   2002     /* Added to handle SDK functions calling esw version,
   2003      * instead of Tomahawk3's version
   2004      */
   2005     if (SOC_IS_TOMAHAWK3(unit)) {
   2006         return bcm_tomahawk3_l2_age_timer_set(unit, age_seconds);
   2007     }
   2008 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   2009 
   2010     L2_INIT(unit);
   2011 
   2012 #if defined(BCM_TRIUMPH3_SUPPORT)
   2013     if (soc_feature(unit, soc_feature_ism_memory)) {
   2014         return bcm_tr3_l2_age_timer_set(unit, age_seconds);
   2015     }
   2016 #endif /* BCM_TRIUMPH3_SUPPORT */    
   2017 
   2018     BCM_IF_ERROR_RETURN
   2019 	(SOC_FUNCTIONS(unit)->soc_age_timer_max_get(unit, &max_value));
   2020 
   2021     if (age_seconds < 0 || age_seconds > max_value) {
   2022         return BCM_E_PARAM;
   2023     }
   2024 
   2025     enabled = age_seconds ? 1 : 0;
   2026 
   2027     rv = _bcm_esw_l2_age_timer_set(unit, age_seconds, enabled);
   2028 
   2029     return rv;
   2030 }
   2031 
   2032 /*
   2033  * Function: *	bcm_esw_l2_age_timer_get
   2034  * Description:
   2035  *	Returns the current age timer value.
   2036  *	The value is 0 if aging is not enabled.
   2037  * Parameters:
   2038  *	unit - StrataSwitch PCI device unit number (driver internal).
   2039  *	age_seconds - Place to store returned age timer value in seconds
   2040  * Returns:
   2041  *	BCM_E_NONE		Success
   2042  *	BCM_E_INTERNAL		Chip access failure
   2043  */
   2044 
   2045 int
   2046 bcm_esw_l2_age_timer_get(int unit, int *age_seconds)
   2047 {
   2048     int			seconds, enabled;
   2049     int			rv;
   2050 
   2051 #if defined(BCM_TOMAHAWK3_SUPPORT)
   2052     /* Added to handle SDK functions calling esw version,
   2053      * instead of Tomahawk3's version
   2054      */
   2055     if (SOC_IS_TOMAHAWK3(unit)) {
   2056         return bcm_tomahawk3_l2_age_timer_get(unit, age_seconds);
   2057     }
   2058 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   2059 
   2060     L2_INIT(unit);
   2061 
   2062     if (age_seconds == NULL) {
   2063         return BCM_E_PARAM;
   2064     }
   2065 
   2066 #if defined(BCM_TRIUMPH3_SUPPORT)
   2067     if (soc_feature(unit, soc_feature_ism_memory)) {
   2068         return bcm_tr3_l2_age_timer_get(unit, age_seconds);
   2069     }
   2070 #endif /* BCM_TRIUMPH3_SUPPORT */    
   2071 
   2072     /*
   2073      * Lock ARLm because soc_arl_freeze() does read/modify/write of
   2074      * AGE_TIMER
   2075      */
   2076 
   2077     SOC_L2X_MEM_LOCK(unit);
   2078     rv = SOC_FUNCTIONS(unit)->soc_age_timer_get(unit, &seconds, &enabled);
   2079     SOC_L2X_MEM_UNLOCK(unit);
   2080 
   2081     BCM_IF_ERROR_RETURN(rv);
   2082 
   2083     if (enabled) {
   2084         *age_seconds = seconds;
   2085     } else {
   2086         *age_seconds = 0;
   2087     }
   2088 
   2089     return BCM_E_NONE;
   2090 }
   2091 
   2092 /*internal function*/
   2093 int
   2094 _bcm_esw_l2_age_timer_get(int unit, int *age_seconds)
   2095 {
   2096     int         rv = BCM_E_NONE;
   2097 #ifdef BCM_XGS_SWITCH_SUPPORT
   2098     int         frozen = 0;
   2099 #endif
   2100     int         enabled;
   2101     /* Lock ARLm b/c soc_arl_freeze() does read/modify/write of AGE_TIMER */
   2102     SOC_L2X_MEM_LOCK(unit);
   2103 
   2104 #ifdef BCM_XGS_SWITCH_SUPPORT
   2105     rv = soc_l2x_is_frozen(unit, SOC_L2X_FROZEN, &frozen);
   2106 
   2107     if (BCM_FAILURE(rv)) {
   2108         frozen = 0;
   2109     }
   2110     if ((!SOC_IS_TRIUMPH3(unit)) && frozen) {
   2111         soc_age_timer_cache_get(unit, age_seconds, &enabled);
   2112 
   2113 		SOC_L2X_MEM_UNLOCK(unit);
   2114         return rv;
   2115     }
   2116 #endif
   2117     rv = SOC_FUNCTIONS(unit)->soc_age_timer_get(unit, age_seconds, &enabled);
   2118 
   2119     SOC_L2X_MEM_UNLOCK(unit);
   2120     return rv;
   2121 }
   2122 
   2123 
   2124 /*
   2125  * Function:
   2126  *	bcm_esw_l2_addr_freeze
   2127  * Description:
   2128  *	Temporarily quiesce ARL from all activity (learning, aging, inserting)
   2129  * include SW operations
   2130  * Parameters:
   2131  *	unit - StrataSwitch PCI device unit number (driver internal).
   2132  * Returns:
   2133  *	BCM_E_NONE		Success
   2134  *	BCM_E_INTERNAL		Chip access failure
   2135  */
   2136 
   2137 int
   2138 bcm_esw_l2_addr_freeze(int unit)
   2139 {
   2140 #if defined(BCM_TOMAHAWK3_SUPPORT)
   2141     /* Added to handle SDK functions calling esw version,
   2142      * instead of Tomahawk3's version
   2143      */
   2144     if (SOC_IS_TOMAHAWK3(unit)) {
   2145         return bcm_tomahawk3_l2_addr_freeze(unit);
   2146     }
   2147 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   2148 
   2149     L2_INIT(unit);
   2150 
   2151 #ifdef BCM_XGS_SWITCH_SUPPORT
   2152     if (soc_feature(unit, soc_feature_arl_hashed)) {
   2153 	return soc_l2x_freeze(unit);
   2154     }
   2155 #endif
   2156 
   2157     return BCM_E_UNAVAIL;
   2158 }
   2159 
   2160 /*
   2161  * Function:
   2162  *	bcm_esw_l2_addr_thaw
   2163  * Description:
   2164  *	Restore normal ARL activity including S/W and H/W activity.
   2165  * Parameters:
   2166  *	unit - StrataSwitch PCI device unit number (driver internal).
   2167  * Returns:
   2168  *	BCM_E_NONE		Success
   2169  *	BCM_E_INTERNAL		Chip access failure
   2170  */
   2171 
   2172 int
   2173 bcm_esw_l2_addr_thaw(int unit)
   2174 {
   2175 #if defined(BCM_TOMAHAWK3_SUPPORT)
   2176     /* Added to handle SDK functions calling esw version,
   2177      * instead of Tomahawk3's version
   2178      */
   2179     if (SOC_IS_TOMAHAWK3(unit)) {
   2180         return bcm_tomahawk3_l2_addr_thaw(unit);
   2181     }
   2182 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   2183 
   2184     L2_INIT(unit);
   2185 
   2186 #if defined(BCM_TRIUMPH3_SUPPORT)
   2187     if (soc_feature(unit, soc_feature_ism_memory)) {
   2188         return soc_tr3_l2_thaw(unit);
   2189     }
   2190 #endif /* BCM_TRIUMPH3_SUPPORT */    
   2191 
   2192 #ifdef BCM_XGS_SWITCH_SUPPORT
   2193     if (soc_feature(unit, soc_feature_arl_hashed)) {
   2194 	return soc_l2x_thaw(unit);
   2195     }
   2196 #endif
   2197 
   2198     return BCM_E_UNAVAIL;
   2199 }
   2200 
   2201 
   2202 /*
   2203  * Function:
   2204  *	_bcm_l2_bpdu_init
   2205  * Description:
   2206  *	Initialize all BPDU addresses to recognize the 802.1D
   2207  *      Spanning Tree address on all chips.
   2208  * Parameters:
   2209  *	unit - StrataSwitch PCI device unit number (driver internal).
   2210  * Returns:
   2211  *	BCM_E_XXX
   2212  * Notes:
   2213  */
   2214 
   2215 static int
   2216 _bcm_l2_bpdu_init(int unit)
   2217 {
   2218     int		i, nbpdu;
   2219     sal_mac_addr_t	mac;
   2220 
   2221     BCM_IF_ERROR_RETURN(bcm_esw_l2_cache_size_get(unit, &nbpdu));
   2222 
   2223     /* Spanning Tree addr (01:80:c2:00:00:00) used as default entries */
   2224     mac[0] = 0x01;
   2225     mac[1] = 0x80;
   2226     mac[2] = 0xc2;
   2227     mac[3] = mac[4] = mac[5] = 0x00;
   2228 
   2229     for (i = 0; i < nbpdu; i++) {
   2230 	BCM_IF_ERROR_RETURN(soc_bpdu_addr_set(unit, i, mac));
   2231     }
   2232     return BCM_E_NONE;
   2233 }
   2234 
   2235 /*
   2236  * Function:
   2237  *	bcm_esw_l2_key_dump
   2238  * Purpose:
   2239  *	Dump the key (VLAN+MAC) portion of a hardware-independent
   2240  *	L2 address for debugging
   2241  * Parameters:
   2242  *	unit - Unit number
   2243  *	pfx - String to print before output
   2244  *	entry - Hardware-independent L2 entry to dump
   2245  *	sfx - String to print after output
   2246  */
   2247 
   2248 int
   2249 bcm_esw_l2_key_dump(int unit, char *pfx, bcm_l2_addr_t *entry, char *sfx)
   2250 {
   2251 #if defined(BCM_TOMAHAWK3_SUPPORT)
   2252     /* Added to handle SDK functions calling esw version,
   2253      * instead of Tomahawk3's version
   2254      */
   2255     if (SOC_IS_TOMAHAWK3(unit)) {
   2256         return bcm_tomahawk3_l2_key_dump(unit, pfx, entry, sfx);
   2257     }
   2258 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   2259 
   2260     LOG_CLI((BSL_META_U(unit,
   2261                         "l2: %sVLAN=0x%03x MAC=0x%02x%02x%02x"
   2262              "%02x%02x%02x%s"), pfx, entry->vid,
   2263              entry->mac[0], entry->mac[1], entry->mac[2],
   2264              entry->mac[3], entry->mac[4], entry->mac[5], sfx));
   2265 
   2266     return BCM_E_NONE;
   2267 }
   2268 
   2269 /*
   2270  * Function:
   2271  *	bcm_esw_l2_conflict_get
   2272  * Purpose:
   2273  *	Given an L2 address, return existing addresses which could conflict.
   2274  * Parameters:
   2275  *	unit		- switch device
   2276  *	addr		- l2 address to search for conflicts
   2277  *	cf_array	- (OUT) list of l2 addresses conflicting with addr
   2278  *	cf_max		- number of entries allocated to cf_array
   2279  *	cf_count	- (OUT) actual number of cf_array entries filled
   2280  * Returns:
   2281  *      BCM_E_XXX
   2282  * Notes:
   2283  *	Given an L2 or L2 multicast address, return any existing L2 or
   2284  *	L2 multicast addresses which might prevent it from being
   2285  *	inserted because a chip resource (like a hash bucket) is full.
   2286  *	This routine could be used if bcm_l2_addr_add or bcm_l2_mcast_add
   2287  *	returns BCM_E_FULL.
   2288  */
   2289 
   2290 int
   2291 bcm_esw_l2_conflict_get(int unit, bcm_l2_addr_t *addr,
   2292          bcm_l2_addr_t *cf_array, int cf_max,
   2293          int *cf_count)
   2294 {
   2295 #if defined(BCM_TOMAHAWK3_SUPPORT)
   2296     /* Added to handle SDK functions calling esw version,
   2297      * instead of Tomahawk3's version
   2298      */
   2299     if (SOC_IS_TOMAHAWK3(unit)) {
   2300         return bcm_tomahawk3_l2_conflict_get(unit, addr, cf_array, cf_max,
   2301                                              cf_count);
   2302     }
   2303 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   2304 
   2305     L2_INIT(unit);
   2306     /*
   2307      * Call chip-dependent handler.
   2308      */
   2309     SOC_IF_ERROR_RETURN
   2310        (mbcm_driver[unit]->mbcm_l2_conflict_get(unit, addr,
   2311                                        cf_array, cf_max, cf_count));
   2312 
   2313     return BCM_E_NONE;
   2314 }
   2315 
   2316 /*
   2317  * Function:
   2318  *      bcm_esw_l2_tunnel_add
   2319  * Purpose:
   2320  *    Add a (MAC, VLAN) for tunnel/MPLS processing, frames
   2321  *      destined to (MAC, VLAN) is subjected to TUNNEL/MPLS processing.
   2322  * Parameters:
   2323  *      unit - StrataXGS unit number
   2324  *      mac  - MAC address
   2325  *      vlan - VLAN ID
   2326  */
   2327 
   2328 int
   2329 bcm_esw_l2_tunnel_add(int unit, bcm_mac_t mac, bcm_vlan_t vlan)
   2330 {
   2331 #if defined(BCM_TOMAHAWK3_SUPPORT)
   2332     /* Added to handle SDK functions calling esw version,
   2333      * instead of Tomahawk3's version
   2334      */
   2335     if (SOC_IS_TOMAHAWK3(unit)) {
   2336         return bcm_tomahawk3_l2_tunnel_add(unit, mac, vlan);
   2337     }
   2338 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   2339 
   2340     L2_INIT(unit);
   2341 
   2342     if (SOC_IS_HURRICANEX(unit) || SOC_IS_GREYHOUND(unit) ||
   2343         SOC_IS_GREYHOUND2(unit)) {
   2344             return BCM_E_UNAVAIL;
   2345     }
   2346 #if defined(BCM_TRIUMPH3_SUPPORT)
   2347     if (soc_feature(unit, soc_feature_ism_memory)) {
   2348         VLAN_CHK_ID(unit, vlan);
   2349         return bcm_tr3_l2_tunnel_add(unit, mac, vlan);
   2350     }
   2351 #endif /* BCM_TRIUMPH3_SUPPORT */    
   2352 
   2353 #if defined (BCM_TRIDENT_SUPPORT) && defined(BCM_MPLS_SUPPORT) && \
   2354         defined(INCLUDE_L3)
   2355     if (SOC_IS_TD_TT(unit) || SOC_IS_KATANAX(unit)) {
   2356         VLAN_CHK_ID(unit, vlan);
   2357 #if defined(BCM_TOMAHAWK_SUPPORT)
   2358         if (SOC_MEM_IS_VALID(unit, MY_STATION_TCAMm)) {
   2359             return bcm_td_metro_myStation_add(unit, mac, vlan, -1, 1);
   2360         }
   2361         else {
   2362             return BCM_E_UNAVAIL;
   2363         }
   2364 #else
   2365         return bcm_td_metro_myStation_add(unit, mac, vlan, -1, 1);
   2366 #endif
   2367     }
   2368 #endif /* BCM_TRIDENT_SUPPORT */
   2369 
   2370 #if defined(BCM_TRIUMPH_SUPPORT) && defined(BCM_MPLS_SUPPORT) && \
   2371         defined(INCLUDE_L3)
   2372     if (SOC_IS_TR_VL(unit)) {
   2373         VLAN_CHK_ID(unit, vlan);
   2374         return bcm_trx_metro_l2_tunnel_add(unit, mac, vlan);
   2375     }
   2376 #endif
   2377 
   2378     return BCM_E_UNAVAIL;
   2379 }
   2380 
   2381 /*
   2382  * Function:
   2383  *      bcm_esw_l2_tunnel_delete
   2384  * Purpose:
   2385  *      Remove a tunnel processing indicator for an L2 address
   2386  * Parameters:
   2387  *      unit - StrataXGS unit number
   2388  *      mac  - MAC address
   2389       vlan - VLAN ID
   2390  */
   2391 
   2392 int
   2393 bcm_esw_l2_tunnel_delete(int unit, bcm_mac_t mac, bcm_vlan_t vlan)
   2394 {
   2395 #if defined(BCM_TOMAHAWK3_SUPPORT)
   2396     /* Added to handle SDK functions calling esw version,
   2397      * instead of Tomahawk3's version
   2398      */
   2399     if (SOC_IS_TOMAHAWK3(unit)) {
   2400         return bcm_tomahawk3_l2_tunnel_delete(unit, mac, vlan);
   2401     }
   2402 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   2403 
   2404     L2_INIT(unit);
   2405 
   2406     if (SOC_IS_HURRICANEX(unit) || SOC_IS_GREYHOUND(unit) ||
   2407         SOC_IS_GREYHOUND2(unit)) {
   2408          return BCM_E_UNAVAIL;
   2409     }
   2410 
   2411 #if defined(BCM_TRIUMPH3_SUPPORT)
   2412     if (soc_feature(unit, soc_feature_ism_memory)) {
   2413         VLAN_CHK_ID(unit, vlan);
   2414         return bcm_tr3_l2_tunnel_delete(unit, mac, vlan);
   2415     }
   2416 #endif /* BCM_TRIUMPH3_SUPPORT */    
   2417 
   2418 #if defined(BCM_TRIDENT_SUPPORT) && defined(BCM_MPLS_SUPPORT) && \
   2419     defined(INCLUDE_L3)
   2420     if (SOC_IS_TD_TT(unit) || SOC_IS_KATANAX(unit)) {
   2421         VLAN_CHK_ID(unit, vlan);
   2422         return bcm_td_metro_myStation_delete(unit, mac, vlan, -1, 1);
   2423     }
   2424 #endif /* BCM_TRIDENT_SUPPORT */
   2425 
   2426 #if defined(BCM_TRIUMPH_SUPPORT) && defined(BCM_MPLS_SUPPORT) && \
   2427     defined(INCLUDE_L3)
   2428     if (SOC_IS_TR_VL(unit)) {
   2429         VLAN_CHK_ID(unit, vlan);
   2430         return bcm_trx_metro_l2_tunnel_delete(unit, mac, vlan);
   2431     }
   2432 #endif
   2433     return BCM_E_UNAVAIL;
   2434 
   2435 }
   2436 
   2437 /*
   2438  * Function:
   2439  *      bcm_l2_tunnel_delete_all
   2440  * Purpose:
   2441  *      Remove all tunnel processing indicating L2 addresses
   2442  * Parameters:
   2443  *      unit - StrataXGS unit number
   2444  */
   2445 
   2446 int
   2447 bcm_esw_l2_tunnel_delete_all(int unit)
   2448 {
   2449 #if defined(BCM_TOMAHAWK3_SUPPORT)
   2450     /* Added to handle SDK functions calling esw version,
   2451      * instead of Tomahawk3's version
   2452      */
   2453     if (SOC_IS_TOMAHAWK3(unit)) {
   2454         return bcm_tomahawk3_l2_tunnel_delete_all(unit);
   2455     }
   2456 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   2457 
   2458     L2_INIT(unit);
   2459 
   2460     if (SOC_IS_HURRICANEX(unit) || SOC_IS_GREYHOUND(unit) ||
   2461         SOC_IS_GREYHOUND2(unit)) {
   2462          return BCM_E_UNAVAIL;
   2463     }
   2464 
   2465 #if defined(BCM_TRIUMPH3_SUPPORT)
   2466     if (soc_feature(unit, soc_feature_ism_memory)) {
   2467         return bcm_tr3_l2_tunnel_delete_all(unit);
   2468     }
   2469 #endif /* BCM_TRIUMPH3_SUPPORT */    
   2470 
   2471 #if defined(BCM_TRIDENT_SUPPORT) && defined(BCM_MPLS_SUPPORT) && \
   2472     defined(INCLUDE_L3)
   2473     if (SOC_IS_TD_TT(unit)||SOC_IS_KATANAX(unit)) {
   2474         return bcm_td_metro_myStation_delete_all(unit);
   2475     }
   2476 #endif /* BCM_TRIDENT_SUPPORT */
   2477 
   2478 #if defined(BCM_TRIUMPH_SUPPORT) && defined(BCM_MPLS_SUPPORT) && \
   2479          defined(INCLUDE_L3)
   2480     if (SOC_IS_TR_VL(unit)) {
   2481         return bcm_trx_metro_l2_tunnel_delete_all(unit);
   2482     }
   2483 #endif
   2484 
   2485     return BCM_E_UNAVAIL;
   2486 }
   2487 
   2488 /*
   2489  * Function:
   2490  *      bcm_esw_l2_clear
   2491  * Purpose:
   2492  *      Clear the L2 layer
   2493  * Parameters:
   2494  *      unit  - BCM unit number
   2495  * Returns:
   2496  *      BCM_E_XXX
   2497  */
   2498 
   2499 int
   2500 bcm_esw_l2_clear(int unit)
   2501 {
   2502 #if defined(BCM_TOMAHAWK3_SUPPORT)
   2503     /* Added to handle SDK functions calling esw version,
   2504      * instead of Tomahawk3's version
   2505      */
   2506     if (SOC_IS_TOMAHAWK3(unit)) {
   2507         return bcm_tomahawk3_l2_clear(unit);
   2508     }
   2509 #endif /* BCM_TOMAHAWK3_SUPPORT */
   2510 
   2511     L2_INIT(unit);
   2512 
   2513 #if defined(BCM_TRIUMPH3_SUPPORT)
   2514     if (soc_feature(unit, soc_feature_ism_memory)) {
   2515         return bcm_tr3_l2_clear(unit);
   2516     }
   2517 #endif /* BCM_TRIUMPH3_SUPPORT */    
   2518 
   2519     if (_bcm_l2_match_ctrl[unit]) {
   2520         _bcm_l2_match_ctrl[unit]->preserved = 1;
   2521     }
   2522 
   2523     bcm_esw_l2_detach(unit);
   2524 
   2525     if (_bcm_l2_match_ctrl[unit]) {
   2526         _bcm_l2_match_ctrl[unit]->preserved = 0;
   2527     }
   2528 
   2529     /*
   2530      * Call chip-dependent initialization
   2531      */
   2532     BCM_IF_ERROR_RETURN(mbcm_driver[unit]->mbcm_l2_init(unit));
   2533 
   2534 #if defined(BCM_XGS_SWITCH_SUPPORT)
   2535     /* Stop l2x thread if callback registration started it. */
   2536     if (l2_data[unit].flags & _BCM_L2X_THREAD_STOP) {
   2537         BCM_IF_ERROR_RETURN(soc_l2x_stop(unit));
   2538     }
   2539 #endif /* BCM_XGS_SWITCH_SUPPORT */
   2540 
   2541     /* Clear l2_data structure */
   2542     l2_data[unit].cb_count = 0;
   2543     l2_data[unit].flags = 0;
   2544     sal_memset(&l2_data[unit].cb, 0, sizeof(l2_data[unit].cb));
   2545 
   2546     _l2_init[unit] = 1;		/* some positive value */
   2547 
   2548     return BCM_E_NONE;
   2549 }
   2550 
   2551 /*
   2552  * MAC learn limit
   2553  */
   2554 #ifdef BCM_TRIUMPH_SUPPORT
   2555 /*
   2556  * Function:
   2557  *      _bcm_tr_l2_learn_limit_system_set
   2558  * Purpose:
   2559  *      Set MAC learn limit for a system 
   2560  * Parameters:
   2561  *      unit  - BCM unit number
   2562  *      flags - Action bitmask 
   2563  *      limit - System limit of MAC addresses to learn
   2564  *              Negative limit disables the check 
   2565  * Returns:
   2566  *      BCM_E_XXX
   2567  */
   2568 STATIC int
   2569 _bcm_tr_l2_learn_limit_system_set(int unit, uint32 flags, int limit)
   2570 {
   2571     uint32 rval, orval;
   2572     int tocpu, drop, enable;
   2573     
   2574     if (limit < 0) {
   2575         tocpu = 0;
   2576         drop = 0;
   2577         limit = soc_mem_index_max(unit, L2Xm);
   2578         enable = 0;
   2579     } else {
   2580         tocpu = flags & BCM_L2_LEARN_LIMIT_ACTION_CPU ? 1 : 0;
   2581         drop = flags & BCM_L2_LEARN_LIMIT_ACTION_DROP ? 1 : 0;
   2582         enable = 1;
   2583     }
   2584 
   2585     /* Starting from Triumph this flag is not supported */
   2586     if (flags & BCM_L2_LEARN_LIMIT_ACTION_PREFER) {
   2587         return BCM_E_PARAM;
   2588     }
   2589 
   2590     BCM_IF_ERROR_RETURN(READ_SYS_MAC_LIMIT_CONTROLr(unit, &rval));
   2591     orval = rval;
   2592     soc_reg_field_set(unit, SYS_MAC_LIMIT_CONTROLr, &rval, 
   2593                       SYS_OVER_LIMIT_TOCPUf, tocpu);
   2594     soc_reg_field_set(unit, SYS_MAC_LIMIT_CONTROLr, &rval,
   2595                       SYS_OVER_LIMIT_DROPf, drop);
   2596     soc_reg_field_set(unit, SYS_MAC_LIMIT_CONTROLr, &rval, SYS_LIMITf, limit);
   2597     soc_reg_field_set(unit, SYS_MAC_LIMIT_CONTROLr, &rval, ENABLEf, enable);
   2598     if (rval != orval) {
   2599         BCM_IF_ERROR_RETURN(WRITE_SYS_MAC_LIMIT_CONTROLr(unit, rval));
   2600     }
   2601 
   2602     return BCM_E_NONE;
   2603 }
   2604 
   2605 /*
   2606  * Function:
   2607  *      _bcm_tr_l2_learn_limit_system_get
   2608  * Purpose:
   2609  *      Get MAC learn limit for a system
   2610  * Parameters:
   2611  *      unit  - BCM unit number
   2612  *      flags - Action bitmask
   2613  *      limit - System limit of MAC addresses to learn
   2614  *              Negative if limit disabled
   2615  * Returns:
   2616  *      BCM_E_XXX
   2617  */
   2618 STATIC int
   2619 _bcm_tr_l2_learn_limit_system_get(int unit, uint32 *flags, int *limit)
   2620 {
   2621     uint32  rval;
   2622 
   2623     BCM_IF_ERROR_RETURN(READ_SYS_MAC_LIMIT_CONTROLr(unit, &rval));
   2624     *flags &= ~(BCM_L2_LEARN_LIMIT_ACTION_DROP |
   2625                 BCM_L2_LEARN_LIMIT_ACTION_CPU);
   2626     if (soc_reg_field_get(unit, SYS_MAC_LIMIT_CONTROLr, rval,
   2627                           SYS_OVER_LIMIT_TOCPUf)) {
   2628         *flags |= BCM_L2_LEARN_LIMIT_ACTION_CPU;
   2629     }
   2630     if (soc_reg_field_get(unit, SYS_MAC_LIMIT_CONTROLr, rval,
   2631                           SYS_OVER_LIMIT_DROPf)) {
   2632         *flags |= BCM_L2_LEARN_LIMIT_ACTION_DROP;
   2633     }
   2634     if (soc_reg_field_get(unit, SYS_MAC_LIMIT_CONTROLr, rval, ENABLEf)) {
   2635         *limit = soc_reg_field_get(unit, SYS_MAC_LIMIT_CONTROLr, rval,
   2636                                    SYS_LIMITf);
   2637     } else {
   2638         *limit = -1;
   2639     }
   2640 
   2641     return BCM_E_NONE;
   2642 }
   2643 
   2644 /*
   2645  * Function:
   2646  *      _bcm_tr_l2_learn_limit_set
   2647  * Purpose:
   2648  *      Set MAC learn limit for a port/trunk/vlan
   2649  * Parameters:
   2650  *      unit  - BCM unit number
   2651  *      mem   - PORT_OR_TRUNK_MAC_LIMITm or VLAN_OR_VFI_MAC_LIMITm
   2652  *      index - for PORT_OR_TRUNK_MAC_LIMITm
   2653  *                  0 - 127: trunk identifier
   2654  *                  128 - 181: port identifier + 128
   2655  *              for VLAN_OR_VFI_MAC_LIMITm
   2656  *                  0 - 4095: VLAN identifier
   2657  *                  4096 - 5119: virtual forwarding instance + 4096
   2658  *      flags - Action bitmask
   2659  *      limit - Max number of MAC addresses can be learned for the specified
   2660  *              identifier
   2661  *              Negative if limit disabled (i.e. unlimit)
   2662  * Returns:
   2663  *      BCM_E_XXX
   2664  */
   2665 STATIC int
   2666 _bcm_tr_l2_learn_limit_set(int unit, soc_mem_t mem, int index, uint32 flags,
   2667                            int limit)
   2668 {
   2669     uint32 entry[SOC_MAX_MEM_WORDS], rval;
   2670     int rv;
   2671 #if defined(BCM_ENDURO_SUPPORT) || defined(BCM_HURRICANE_SUPPORT)
   2672     port_or_trunk_mac_limit_entry_t init_entry;
   2673     uint32 max_limit = BCM_MAC_LIMIT_MAX;
   2674 #endif /* BCM_ENDURO_SUPPORT || BCM_HURRICANE_SUPPORT */
   2675 
   2676     if (limit < 0) {
   2677         soc_mem_lock(unit, mem);
   2678         rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, index,
   2679                            soc_mem_entry_null(unit, mem));
   2680 #if defined(BCM_ENDURO_SUPPORT) || defined(BCM_HURRICANE_SUPPORT)
   2681         if (SOC_IS_ENDURO(unit) || SOC_IS_HURRICANEX(unit) ||
   2682             SOC_IS_GREYHOUND(unit) || SOC_IS_GREYHOUND2(unit)) {
   2683             /* Reset Limit value is different than soc_mem_entry_null for different SKUs */
   2684             soc_mem_field32_set(unit, mem, &init_entry, LIMITf, max_limit);
   2685             rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, index, &init_entry);
   2686         }
   2687 #endif /* BCM_ENDURO_SUPPORT || BCM_HURRICANE_SUPPORT */
   2688         soc_mem_unlock(unit, mem);
   2689         return rv;
   2690     }
   2691 
   2692     soc_mem_lock(unit, mem);
   2693     rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, index, &entry);
   2694     if (BCM_SUCCESS(rv)) {
   2695         soc_mem_field32_set(unit, mem, &entry, OVER_LIMIT_TOCPUf,
   2696                             flags & BCM_L2_LEARN_LIMIT_ACTION_CPU ? 1 : 0);
   2697         soc_mem_field32_set(unit, mem, &entry, OVER_LIMIT_DROPf,
   2698                             flags & BCM_L2_LEARN_LIMIT_ACTION_DROP ? 1 : 0);
   2699         soc_mem_field32_set(unit, mem, &entry, LIMITf, limit);
   2700         rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, index, &entry);
   2701     }
   2702     soc_mem_unlock(unit, mem);
   2703 
   2704     if (BCM_FAILURE(rv)) {
   2705         return rv;
   2706     }
   2707 
   2708     BCM_IF_ERROR_RETURN(READ_SYS_MAC_LIMIT_CONTROLr(unit, &rval));
   2709     soc_reg_field_set(unit, SYS_MAC_LIMIT_CONTROLr, &rval, ENABLEf, 1);
   2710     return (WRITE_SYS_MAC_LIMIT_CONTROLr(unit, rval));
   2711 }
   2712 
   2713 /*
   2714  * Function:
   2715  *      _bcm_tr_l2_learn_limit_get
   2716  * Purpose:
   2717  *      Get MAC learn limit for a port/trunk/vlan
   2718  * Parameters:
   2719  *      unit  - BCM unit number
   2720  *      mem   - PORT_OR_TRUNK_MAC_LIMITm or VLAN_OR_VFI_MAC_LIMITm
   2721  *      index - for PORT_OR_TRUNK_MAC_LIMITm
   2722  *                  0 - 127: trunk identifier
   2723  *                  128 - 181: port identifier + 128
   2724  *              for VLAN_OR_VFI_MAC_LIMITm
   2725  *                  0 - 4095: VLAN identifier
   2726  *                  4096 - 5119: virtual forwarding instance + 4096
   2727  *      flags - Action bitmask
   2728  *      limit - Max number of MAC addresses can be learned for the specified
   2729  *              identifier
   2730  *              Negative if limit disabled (i.e. unlimit)
   2731  * Returns:
   2732  *      BCM_E_XXX
   2733  */
   2734 STATIC int
   2735 _bcm_tr_l2_learn_limit_get(int unit, soc_mem_t mem, int index, uint32* flags,
   2736                            int* limit)
   2737 {
   2738     uint32 entry[SOC_MAX_MEM_WORDS];
   2739 
   2740     SOC_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ANY, index, &entry));
   2741     *flags &= ~(BCM_L2_LEARN_LIMIT_ACTION_DROP |
   2742                 BCM_L2_LEARN_LIMIT_ACTION_CPU);
   2743     if (soc_mem_field32_get(unit, mem, &entry, OVER_LIMIT_DROPf)) {
   2744         *flags |= BCM_L2_LEARN_LIMIT_ACTION_DROP;
   2745     }
   2746     if (soc_mem_field32_get(unit, mem, &entry, OVER_LIMIT_TOCPUf)) {
   2747         *flags |= BCM_L2_LEARN_LIMIT_ACTION_CPU;
   2748     }
   2749     *limit = soc_mem_field32_get(unit, mem, &entry, LIMITf);
   2750 
   2751     return BCM_E_NONE;
   2752 }
   2753 #endif
   2754 
   2755 #if defined(BCM_ENDURO_SUPPORT) || defined(BCM_HURRICANE_SUPPORT)
   2756 /*
   2757  * Function:
   2758  *      _bcm_enduro_l2_learn_limit_init
   2759  * Purpose:
   2760  *      Init the system to support MAC learn limit
   2761  * Parameters:
   2762  *      unit  - BCM unit number
   2763  * Returns:
   2764  *      BCM_E_XXX
   2765  */
   2766 STATIC int
   2767 _bcm_enduro_l2_learn_limit_init(int unit)
   2768 {
   2769     uint32 maxInitVal;
   2770     int rv, idx, idx_min, idx_max;
   2771     uint8 *port_or_trunk_mac_limit_buf = NULL;
   2772     uint8 *vlan_or_vfi_mac_limit_buf = NULL;
   2773     vlan_or_vfi_mac_limit_entry_t   *vlan_or_vfi_mac_limit_entry = NULL;
   2774     port_or_trunk_mac_limit_entry_t *port_or_trunk_mac_limit_entry = NULL;
   2775     maxInitVal = BCM_MAC_LIMIT_MAX; 
   2776 
   2777     BCM_IF_ERROR_RETURN(_bcm_tr_l2_learn_limit_system_set(unit, 0, -1));
   2778     BCM_IF_ERROR_RETURN
   2779         (soc_mem_clear(unit, PORT_OR_TRUNK_MAC_LIMITm, COPYNO_ALL, FALSE));
   2780     BCM_IF_ERROR_RETURN
   2781         (soc_mem_clear(unit, VLAN_OR_VFI_MAC_LIMITm, COPYNO_ALL, FALSE));
   2782 
   2783     /* PORT_OR_TRUNK_MAC_LIMIT table*/
   2784     port_or_trunk_mac_limit_buf = soc_cm_salloc(unit,
   2785                    SOC_MEM_TABLE_BYTES(unit,PORT_OR_TRUNK_MAC_LIMITm),
   2786                    "port_or_trunk");
   2787     if (port_or_trunk_mac_limit_buf == NULL) {
   2788         return BCM_E_MEMORY;
   2789     }
   2790 
   2791     idx_min = soc_mem_index_min(unit, PORT_OR_TRUNK_MAC_LIMITm); 
   2792     idx_max = soc_mem_index_max(unit, PORT_OR_TRUNK_MAC_LIMITm);
   2793     rv = soc_mem_read_range(unit, PORT_OR_TRUNK_MAC_LIMITm,
   2794                             MEM_BLOCK_ANY, idx_min, idx_max,
   2795                             port_or_trunk_mac_limit_buf);
   2796     
   2797     if (BCM_FAILURE(rv)) {
   2798         goto cleanup;
   2799     }
   2800 
   2801     for(idx = idx_min; idx<= idx_max; idx++) {
   2802         port_or_trunk_mac_limit_entry = 
   2803             soc_mem_table_idx_to_pointer(unit, PORT_OR_TRUNK_MAC_LIMITm,
   2804                                         port_or_trunk_mac_limit_entry_t *,
   2805                                         port_or_trunk_mac_limit_buf,
   2806                                         idx);
   2807         soc_PORT_OR_TRUNK_MAC_LIMITm_field32_set(unit,
   2808                             port_or_trunk_mac_limit_entry,
   2809                             LIMITf, maxInitVal);
   2810     }
   2811     rv = soc_mem_write_range(unit, PORT_OR_TRUNK_MAC_LIMITm, MEM_BLOCK_ALL,
   2812                              idx_min, idx_max, port_or_trunk_mac_limit_buf);
   2813     if (BCM_FAILURE(rv)) {
   2814         goto cleanup;
   2815     }
   2816         
   2817     /* VLAN_OR_VFI_MAC_LIMIT table*/
   2818     vlan_or_vfi_mac_limit_buf = soc_cm_salloc(unit,
   2819                    SOC_MEM_TABLE_BYTES(unit, VLAN_OR_VFI_MAC_LIMITm),
   2820                    "vlan_or_vfi");
   2821     if (vlan_or_vfi_mac_limit_buf == NULL) {
   2822         rv = BCM_E_MEMORY;
   2823         goto cleanup;
   2824     }
   2825        
   2826     idx_min = soc_mem_index_min(unit, VLAN_OR_VFI_MAC_LIMITm); 
   2827     idx_max = soc_mem_index_max(unit, VLAN_OR_VFI_MAC_LIMITm);
   2828     rv = soc_mem_read_range(unit, VLAN_OR_VFI_MAC_LIMITm,
   2829                             MEM_BLOCK_ANY, idx_min, idx_max,
   2830                             vlan_or_vfi_mac_limit_buf);
   2831     
   2832     if (BCM_FAILURE(rv)) {
   2833         goto cleanup;
   2834     }
   2835 
   2836     for(idx = idx_min; idx<= idx_max; idx++) {
   2837         vlan_or_vfi_mac_limit_entry = 
   2838             soc_mem_table_idx_to_pointer(unit, VLAN_OR_VFI_MAC_LIMITm,
   2839                                         vlan_or_vfi_mac_limit_entry_t *,
   2840                                         vlan_or_vfi_mac_limit_buf,
   2841                                         idx);
   2842         soc_PORT_OR_TRUNK_MAC_LIMITm_field32_set(unit,
   2843                             vlan_or_vfi_mac_limit_entry,
   2844                             LIMITf, maxInitVal);
   2845     }
   2846     rv = soc_mem_write_range(unit, VLAN_OR_VFI_MAC_LIMITm, MEM_BLOCK_ALL,
   2847                              idx_min, idx_max, vlan_or_vfi_mac_limit_buf);
   2848     if (BCM_FAILURE(rv)) {
   2849         goto cleanup;
   2850     }
   2851         
   2852 
   2853 cleanup:
   2854 
   2855     if (port_or_trunk_mac_limit_buf) {
   2856         soc_cm_sfree(unit, port_or_trunk_mac_limit_buf);
   2857     }
   2858 
   2859     if (vlan_or_vfi_mac_limit_buf) {
   2860         soc_cm_sfree(unit, vlan_or_vfi_mac_limit_buf);
   2861     }
   2862 
   2863     return rv;
   2864 }
   2865 #endif /* BCM_ENDURO_SUPPORT || BCM_HURRICANE_SUPPORT */
   2866 
   2867 #define PORT_COUNT(unit) (SOC_INFO(unit).port_num)
   2868 
   2869 #if defined(BCM_TRIUMPH_SUPPORT) || defined(BCM_RAPTOR_SUPPORT)
   2870 /*
   2871  * Function:
   2872  *      _bcm_l2_learn_limit_porttrunk_set
   2873  * Purpose:
   2874  *      helper function to configure registers
   2875  * Parameters:
   2876  *      unit  - BCM unit number
   2877  *      port_tgid - Port or Trunk number
   2878  *      flags - Action bitmask 
   2879  *      limit - Per port limit of MAC addresses to learn 
   2880  *              Negative if limit disabled  
   2881  * Returns:
   2882  *      BCM_E_XXX
   2883  */
   2884 
   2885 STATIC int
   2886 _bcm_l2_learn_limit_porttrunk_set(int unit, int port_tgid, uint32 flags,
   2887                                   int limit)
   2888 {
   2889     int     rv = BCM_E_NONE;
   2890     port_or_trunk_mac_limit_entry_t lim_entry;
   2891     port_or_trunk_mac_action_entry_t act_entry;
   2892 
   2893 
   2894     if (limit > BCM_MAC_LIMIT_MAX){
   2895         return BCM_E_PARAM;
   2896     }
   2897     /* Negative limit disables the check */
   2898     if (limit < 0) {
   2899         soc_mem_lock(unit, PORT_OR_TRUNK_MAC_LIMITm);
   2900 
   2901         rv = READ_PORT_OR_TRUNK_MAC_LIMITm(unit, MEM_BLOCK_ANY, port_tgid, &lim_entry);
   2902         if ( BCM_E_NONE == rv) {
   2903             soc_PORT_OR_TRUNK_MAC_LIMITm_field32_set(unit, &lim_entry, 
   2904                                                      PORT_TRUNK_MAC_LIMITf,
   2905                                                      BCM_MAC_LIMIT_MAX);
   2906             rv = WRITE_PORT_OR_TRUNK_MAC_LIMITm(unit, MEM_BLOCK_ALL, 
   2907                                                 port_tgid, &lim_entry);
   2908         }
   2909         soc_mem_unlock(unit, PORT_OR_TRUNK_MAC_LIMITm);
   2910 
   2911         return rv;
   2912     }
   2913 
   2914 
   2915     /* If everything is OK - configure the registers */
   2916     soc_mem_lock(unit, PORT_OR_TRUNK_MAC_LIMITm);
   2917     
   2918     rv = READ_PORT_OR_TRUNK_MAC_LIMITm(unit, MEM_BLOCK_ANY, port_tgid, &lim_entry);
   2919     if (BCM_E_NONE == rv) {
   2920         soc_PORT_OR_TRUNK_MAC_LIMITm_field32_set(unit, &lim_entry, 
   2921                                                  PORT_TRUNK_MAC_LIMITf,
   2922                                                  limit);
   2923         rv = WRITE_PORT_OR_TRUNK_MAC_LIMITm(unit, MEM_BLOCK_ALL, 
   2924                                             port_tgid, &lim_entry);
   2925     }
   2926     soc_mem_unlock(unit, PORT_OR_TRUNK_MAC_LIMITm);
   2927 
   2928     BCM_IF_ERROR_RETURN(rv);
   2929 
   2930     soc_mem_lock(unit, PORT_OR_TRUNK_MAC_ACTIONm);
   2931     
   2932     rv = READ_PORT_OR_TRUNK_MAC_ACTIONm(unit, MEM_BLOCK_ANY, port_tgid, &act_entry);
   2933     if (BCM_E_NONE == rv) {
   2934         soc_mem_field32_set(unit, PORT_OR_TRUNK_MAC_ACTIONm, &act_entry,
   2935                             OVER_LIMIT_DROPf,
   2936                             flags & BCM_L2_LEARN_LIMIT_ACTION_DROP ? 1 : 0);
   2937         soc_mem_field32_set(unit, PORT_OR_TRUNK_MAC_ACTIONm, &act_entry,
   2938                             OVER_LIMIT_TOCPUf,
   2939                             flags & BCM_L2_LEARN_LIMIT_ACTION_CPU ? 1 : 0);
   2940         rv = WRITE_PORT_OR_TRUNK_MAC_ACTIONm(unit, MEM_BLOCK_ALL, port_tgid, &act_entry);
   2941     }
   2942     soc_mem_unlock(unit, PORT_OR_TRUNK_MAC_ACTIONm);
   2943 
   2944     return rv;
   2945 }
   2946 
   2947 /*
   2948  * Function:
   2949  *      _bcm_l2_learn_limit_porttrunk_get
   2950  * Purpose:
   2951  *      helper function to configure registers
   2952  * Parameters:
   2953  *      unit  - BCM unit number
   2954  *      port_tgid - Port or trunk number 
   2955  *      flags - Action bitmask 
   2956  *      limit - Per port limit of MAC addresses to learn 
   2957  *              Negative limit disables the check 
   2958  * Returns:
   2959  *      BCM_E_XXX
   2960  */
   2961 
   2962 STATIC int
   2963 _bcm_l2_learn_limit_porttrunk_get(int unit, int port_tgid, uint32 *flags,
   2964                                   int *limit)
   2965 {
   2966     int     org_action;
   2967     port_or_trunk_mac_limit_entry_t lim_entry;
   2968     port_or_trunk_mac_action_entry_t act_entry;
   2969 
   2970     if (!soc_feature(unit, soc_feature_mac_learn_limit)) {
   2971         return BCM_E_UNAVAIL;
   2972     }
   2973 
   2974     *flags = 0;
   2975 
   2976     BCM_IF_ERROR_RETURN
   2977         (READ_PORT_OR_TRUNK_MAC_LIMITm(unit,
   2978                                        MEM_BLOCK_ANY,
   2979                                        port_tgid,
   2980                                        &lim_entry));
   2981     *limit = soc_PORT_OR_TRUNK_MAC_LIMITm_field32_get(unit, &lim_entry, 
   2982                                                  PORT_TRUNK_MAC_LIMITf);
   2983     BCM_IF_ERROR_RETURN
   2984         (READ_PORT_OR_TRUNK_MAC_ACTIONm(unit,
   2985                                         MEM_BLOCK_ANY,
   2986                                         port_tgid,
   2987                                         &act_entry));
   2988     org_action = soc_PORT_OR_TRUNK_MAC_ACTIONm_field32_get(unit, &act_entry,
   2989                                                   OVER_LIMIT_DROPf);
   2990     if (org_action) {
   2991         *flags |= BCM_L2_LEARN_LIMIT_ACTION_DROP;
   2992     }
   2993     org_action = soc_PORT_OR_TRUNK_MAC_ACTIONm_field32_get(unit, &act_entry,
   2994                                                   OVER_LIMIT_TOCPUf);
   2995     if (org_action) {
   2996         *flags |= BCM_L2_LEARN_LIMIT_ACTION_CPU;
   2997     }
   2998 
   2999     return BCM_E_NONE;
   3000 }
   3001 
   3002 /*
   3003  * Function:
   3004  *      _bcm_l2_learn_limit_init
   3005  * Purpose:
   3006  *      Init the system to support MAC learn limit
   3007  * Parameters:
   3008  *      unit  - BCM unit number
   3009  * Returns:
   3010  *      BCM_E_XXX
   3011  */
   3012 STATIC int
   3013 _bcm_l2_learn_limit_init(int unit)
   3014 {
   3015 
   3016     bcm_port_t                          port;
   3017     bcm_trunk_t                         trunk;
   3018     bcm_trunk_t                         trunk_index;
   3019     mac_limit_port_map_table_entry_t    entry;
   3020     int                                 rv = BCM_E_NONE;
   3021     uint32                              maxInitVal, zeroInitVal;
   3022 
   3023     if (soc_feature(unit, soc_feature_mac_learn_limit)) {
   3024 #if defined(BCM_ENDURO_SUPPORT) || defined(BCM_HURRICANE_SUPPORT)
   3025         if (SOC_IS_ENDURO(unit) || SOC_IS_HURRICANEX(unit) ||
   3026             SOC_IS_GREYHOUND(unit) || SOC_IS_GREYHOUND2(unit)) {
   3027             /* Reset Limit value is different than soc_mem_entry_null for different SKUs */
   3028             return _bcm_enduro_l2_learn_limit_init(unit);
   3029         }
   3030 #endif /* BCM_ENDURO_SUPPORT || BCM_HURRICANE_SUPPORT */
   3031 #ifdef BCM_TRIUMPH_SUPPORT
   3032         if (SOC_IS_TR_VL(unit)) {
   3033             _bcm_tr_l2_learn_limit_system_set(unit, 0, -1);
   3034             BCM_IF_ERROR_RETURN
   3035             (soc_mem_clear(unit, PORT_OR_TRUNK_MAC_LIMITm, COPYNO_ALL, FALSE));
   3036             BCM_IF_ERROR_RETURN
   3037             (soc_mem_clear(unit, VLAN_OR_VFI_MAC_LIMITm, COPYNO_ALL, FALSE));
   3038             return BCM_E_NONE;
   3039         }
   3040 #endif
   3041         maxInitVal = BCM_MAC_LIMIT_MAX; 
   3042         zeroInitVal = 0;
   3043 
   3044         /* Initialize all learning limits to max and disable feature */
   3045         BCM_IF_ERROR_RETURN(WRITE_MAC_LIMIT_ENABLEr(unit, zeroInitVal));
   3046         BCM_IF_ERROR_RETURN(WRITE_SYS_MAC_LIMITr(unit, maxInitVal));
   3047         /* Map initial port/trunk to counters */
   3048         soc_mem_lock(unit, MAC_LIMIT_PORT_MAP_TABLEm);
   3049         soc_mem_lock(unit, MAC_LIMIT_TRUNK_MAP_TABLEm);
   3050         soc_mem_lock(unit, PORT_OR_TRUNK_MAC_LIMITm);
   3051         soc_mem_lock(unit, PORT_OR_TRUNK_MAC_ACTIONm);
   3052         PBMP_ALL_ITER(unit, port) {
   3053             /* Initialize the HW tables for port map table*/
   3054             rv = WRITE_PORT_OR_TRUNK_MAC_LIMITm(unit, MEM_BLOCK_ALL, 
   3055                                                 port, &maxInitVal);
   3056             if (BCM_FAILURE(rv)) {
   3057                 goto done;
   3058             }
   3059 
   3060             rv = WRITE_PORT_OR_TRUNK_MAC_ACTIONm(unit, MEM_BLOCK_ALL, 
   3061                                                  port, &zeroInitVal );
   3062             if (BCM_FAILURE(rv)) {
   3063                 goto done;
   3064             }
   3065 
   3066             rv = READ_MAC_LIMIT_PORT_MAP_TABLEm(unit, MEM_BLOCK_ANY, 
   3067                                                 port, &entry);
   3068             if (BCM_SUCCESS(rv)) {
   3069                 soc_MAC_LIMIT_PORT_MAP_TABLEm_field32_set(unit, &entry,
   3070                                                           INDEXf, port);
   3071                 rv = WRITE_MAC_LIMIT_PORT_MAP_TABLEm(unit, MEM_BLOCK_ALL, 
   3072                                                      port, &entry);
   3073             }
   3074             if (BCM_FAILURE(rv)) {
   3075                 goto done;
   3076             }
   3077         }
   3078         /* Initialize the HW tables for trunk map table */
   3079         for (trunk = 0;
   3080              trunk < soc_mem_index_count(unit, MAC_LIMIT_TRUNK_MAP_TABLEm);
   3081              trunk ++ ) {
   3082             trunk_index = trunk + PORT_COUNT(unit);
   3083             rv = WRITE_PORT_OR_TRUNK_MAC_LIMITm(unit, MEM_BLOCK_ALL,
   3084                                                 trunk_index, &maxInitVal);
   3085             if (BCM_FAILURE(rv)) {
   3086                 goto done;
   3087             }
   3088             rv = READ_MAC_LIMIT_TRUNK_MAP_TABLEm(unit, MEM_BLOCK_ALL,
   3089                                                  trunk, &entry);
   3090             if (BCM_SUCCESS(rv)) {
   3091                 soc_MAC_LIMIT_TRUNK_MAP_TABLEm_field32_set(unit, &entry,
   3092                                                            INDEXf, trunk);
   3093                 rv = WRITE_MAC_LIMIT_TRUNK_MAP_TABLEm(unit, MEM_BLOCK_ALL, 
   3094                                                       trunk, &entry);
   3095             }
   3096             if (BCM_FAILURE(rv)) {
   3097                 goto done;
   3098             }
   3099         }
   3100 done:
   3101         soc_mem_unlock(unit, MAC_LIMIT_PORT_MAP_TABLEm);
   3102         soc_mem_unlock(unit, MAC_LIMIT_TRUNK_MAP_TABLEm);
   3103         soc_mem_unlock(unit, PORT_OR_TRUNK_MAC_LIMITm);
   3104         soc_mem_unlock(unit, PORT_OR_TRUNK_MAC_ACTIONm);
   3105 
   3106         return rv;
   3107     } 
   3108 
   3109     return BCM_E_UNAVAIL;
   3110 }
   3111 
   3112 
   3113 /*
   3114  * Function:
   3115  *      _bcm_l2_learn_limit_system_set
   3116  * Purpose:
   3117  *      Set MAC learn limit for a system 
   3118  * Parameters:
   3119  *      unit  - BCM unit number
   3120  *      flags - Action bitmask 
   3121  *      limit - System limit of MAC addresses to learn
   3122  *              Negative limit disables the check 
   3123  * Returns:
   3124  *      BCM_E_XXX
   3125  */
   3126 STATIC int
   3127 _bcm_l2_learn_limit_system_set(int unit, uint32 flags, int limit)
   3128 {
   3129     uint32  limit_enable, limit_action;
   3130     int org_limit = 0;
   3131     
   3132     if (!soc_feature(unit, soc_feature_mac_learn_limit)) {
   3133         return BCM_E_UNAVAIL;
   3134     }
   3135 
   3136     if (limit > BCM_MAC_LIMIT_MAX){
   3137         return BCM_E_PARAM;
   3138     }
   3139 
   3140     /* Negative limit disables the check */
   3141     if (limit < 0) {
   3142         BCM_IF_ERROR_RETURN(READ_SYS_MAC_LIMITr(unit, &limit_enable));
   3143         soc_reg_field_set(unit, SYS_MAC_LIMITr, &limit_enable, 
   3144                           SYS_MAC_LIMITf, BCM_MAC_LIMIT_MAX);
   3145         BCM_IF_ERROR_RETURN(WRITE_SYS_MAC_LIMITr(unit, limit_enable));
   3146 
   3147         return BCM_E_NONE;
   3148     }
   3149 
   3150     /* If everything is OK - configure the registers */
   3151     /* First configure the Limit and then enable */
   3152     
   3153 
   3154     BCM_IF_ERROR_RETURN(READ_SYS_MAC_LIMITr(unit, &limit_enable));
   3155     org_limit = soc_reg_field_get(unit, SYS_MAC_LIMITr, limit_enable, 
   3156                                   SYS_MAC_LIMITf);
   3157     if (org_limit != limit) {
   3158         soc_reg_field_set(unit, SYS_MAC_LIMITr, &limit_enable, 
   3159                           SYS_MAC_LIMITf, limit);
   3160         BCM_IF_ERROR_RETURN(WRITE_SYS_MAC_LIMITr(unit, limit_enable));
   3161     }
   3162 
   3163     BCM_IF_ERROR_RETURN(READ_SYS_MAC_ACTIONr(unit, &limit_action));
   3164     /*
   3165      * Need to reset the action bit if the flasg is not set.
   3166      */
   3167     soc_reg_field_set(unit,
   3168                       SYS_MAC_ACTIONr,
   3169                       &limit_action,
   3170                       OVER_LIMIT_DROPf, 
   3171                       (flags & BCM_L2_LEARN_LIMIT_ACTION_DROP) ? 1 : 0);
   3172     soc_reg_field_set(unit,
   3173                       SYS_MAC_ACTIONr,
   3174                       &limit_action, 
   3175                       OVER_LIMIT_TOCPUf,
   3176                       (flags & BCM_L2_LEARN_LIMIT_ACTION_CPU) ? 1 : 0);
   3177     soc_reg_field_set(unit,
   3178                       SYS_MAC_ACTIONr,
   3179                       &limit_action, 
   3180                       MAC_LIMIT_USE_SYS_ACTIONf,
   3181                       (flags & BCM_L2_LEARN_LIMIT_ACTION_PREFER) ? 1 : 0);
   3182 
   3183     BCM_IF_ERROR_RETURN(WRITE_SYS_MAC_ACTIONr(unit, limit_action));
   3184 
   3185 
   3186     return BCM_E_NONE;
   3187 }
   3188 
   3189 /*
   3190  * Function:
   3191  *      _bcm_l2_learn_limit_system_get
   3192  * Purpose:
   3193  *      Get MAC learn limit for a system 
   3194  * Parameters:
   3195  *      unit  - BCM unit number
   3196  *      flags - Action bitmask 
   3197  *      limit - System limit of MAC addresses to learn
   3198  *              Negative if limit disabled  
   3199  * Returns:
   3200  *      BCM_E_XXX
   3201  */
   3202 STATIC int
   3203 _bcm_l2_learn_limit_system_get(int unit, uint32 *flags, int *limit)
   3204 {
   3205        uint32  limit_enable, limit_action;
   3206        int     org_limit, org_action;
   3207 
   3208        if (!soc_feature(unit, soc_feature_mac_learn_limit)) {
   3209            return BCM_E_UNAVAIL;
   3210        }
   3211 
   3212        BCM_IF_ERROR_RETURN(READ_MAC_LIMIT_ENABLEr(unit, &limit_enable));
   3213        org_limit = soc_reg_field_get(unit, MAC_LIMIT_ENABLEr, limit_enable, 
   3214                                      ENABLEf);
   3215 
   3216        *flags = 0;
   3217        if (!org_limit) {
   3218            *limit = -1;
   3219            return BCM_E_NONE;
   3220        }
   3221 
   3222        BCM_IF_ERROR_RETURN(READ_SYS_MAC_LIMITr(unit, &limit_enable));
   3223        *limit = soc_reg_field_get(unit, SYS_MAC_LIMITr, limit_enable, 
   3224                                   SYS_MAC_LIMITf);
   3225 
   3226        /*
   3227         *  In case of MAC learn limit was disabled but somehow 
   3228         *  enable bit was set 
   3229         */
   3230        if (*limit > BCM_MAC_LIMIT_MAX) {
   3231            *limit = -1 ;
   3232            return BCM_E_NONE;
   3233        }
   3234 
   3235        BCM_IF_ERROR_RETURN(READ_SYS_MAC_ACTIONr(unit, &limit_action));
   3236        org_action = soc_reg_field_get(unit, SYS_MAC_ACTIONr, limit_action, 
   3237                                       OVER_LIMIT_DROPf);
   3238        if (org_action) {
   3239            *flags |= BCM_L2_LEARN_LIMIT_ACTION_DROP;
   3240        }
   3241        org_action = soc_reg_field_get(unit, SYS_MAC_ACTIONr, limit_action, 
   3242                                       OVER_LIMIT_TOCPUf);
   3243        if (org_action) {
   3244            *flags |= BCM_L2_LEARN_LIMIT_ACTION_CPU;
   3245        }
   3246        org_action = soc_reg_field_get(unit, SYS_MAC_ACTIONr, limit_action, 
   3247                                       MAC_LIMIT_USE_SYS_ACTIONf);
   3248        if (org_action) {
   3249            *flags |= BCM_L2_LEARN_LIMIT_ACTION_PREFER;
   3250        }
   3251 
   3252        return BCM_E_NONE;
   3253 }
   3254 /*
   3255  * Function:
   3256  *      _bcm_l2_learn_limit_port_set
   3257  * Purpose:
   3258  *      Set MAC learn limit for a specific port 
   3259  * Parameters:
   3260  *      unit  - BCM unit number
   3261  *      port - Port number
   3262  *      flags - Action bitmask 
   3263  *      limit - Per port limit of MAC addresses to learn 
   3264  *              Negative if limit disabled  
   3265  * Returns:
   3266  *      BCM_E_XXX
   3267  */
   3268 STATIC int
   3269 _bcm_l2_learn_limit_port_set(int unit, bcm_port_t port, uint32 flags,
   3270                              int limit)
   3271 {
   3272     int                                 rv = BCM_E_NONE;
   3273     mac_limit_port_map_table_entry_t    entry;
   3274     source_trunk_map_table_entry_t      trunk_entry;
   3275     bcm_module_t my_modid;
   3276     int index;
   3277 
   3278     if (!SOC_UNIT_VALID(unit)) {
   3279         return BCM_E_UNIT;
   3280     }
   3281     if (!SOC_PORT_VALID(unit, port)) {
   3282         return BCM_E_PORT;
   3283     }
   3284 
   3285     if (0 == soc_feature(unit, soc_feature_mac_learn_limit)) {
   3286         return (BCM_E_UNAVAIL);
   3287     }
   3288 
   3289     /* Get local module id. */
   3290     BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &my_modid));
   3291 
   3292     /* Calculate table index. */
   3293     BCM_IF_ERROR_RETURN(_bcm_esw_src_mod_port_table_index_get(unit, 
   3294         my_modid, port, &index));
   3295 
   3296     SOC_IF_ERROR_RETURN(READ_SOURCE_TRUNK_MAP_TABLEm(unit, MEM_BLOCK_ANY,
   3297                                                      index, &trunk_entry));
   3298     /* Normal port will be encoded as 0 */
   3299     if (soc_SOURCE_TRUNK_MAP_TABLEm_field32_get(unit, &trunk_entry,
   3300                                                 PORT_TYPEf)) {
   3301         return BCM_E_CONFIG;
   3302     }
   3303     rv = _bcm_l2_learn_limit_porttrunk_set(unit, port, flags, limit);
   3304     if (rv != BCM_E_NONE) {
   3305         return rv;
   3306     }
   3307     soc_mem_lock(unit, MAC_LIMIT_PORT_MAP_TABLEm);
   3308     /* Map port to it's counter */
   3309     rv = READ_MAC_LIMIT_PORT_MAP_TABLEm(unit, MEM_BLOCK_ANY, 
   3310                                         port, &entry);
   3311     if (BCM_E_NONE == rv) {
   3312         soc_MAC_LIMIT_PORT_MAP_TABLEm_field32_set(unit, &entry,
   3313                                                   INDEXf, port);
   3314         rv = WRITE_MAC_LIMIT_PORT_MAP_TABLEm(unit, MEM_BLOCK_ALL, 
   3315                                              port, &entry);
   3316     }
   3317     soc_mem_unlock(unit, MAC_LIMIT_PORT_MAP_TABLEm);
   3318 
   3319     return rv;
   3320 }
   3321 
   3322 /*
   3323  * Function:
   3324  *      _bcm_l2_learn_limit_port_get
   3325  * Purpose:
   3326  *      Get MAC learn limit for a specific port 
   3327  * Parameters:
   3328  *      unit  - BCM unit number
   3329  *      port - Port number
   3330  *      flags - Action bitmask 
   3331  *      limit - Per port limit of MAC addresses to learn 
   3332  *              Negative limit disables the check 
   3333  * Returns:
   3334  *      BCM_E_XXX
   3335  */
   3336 STATIC int
   3337 _bcm_l2_learn_limit_port_get(int unit, bcm_port_t port, uint32 *flags,
   3338                              int *limit)
   3339 {
   3340     int                                 rv = BCM_E_NONE;
   3341     int                                 hw_index;
   3342     source_trunk_map_table_entry_t      trunk_entry;
   3343     bcm_module_t my_modid;
   3344     int index;
   3345 
   3346     if (!SOC_UNIT_VALID(unit)) {
   3347         return BCM_E_UNIT;
   3348     }
   3349     if (!SOC_PORT_VALID(unit, port)) {
   3350         return BCM_E_PORT;
   3351     }
   3352     if (0 == soc_feature(unit, soc_feature_mac_learn_limit)) {
   3353         return (BCM_E_UNAVAIL);
   3354     }
   3355 
   3356     /* Get local module id. */
   3357     BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &my_modid));
   3358 
   3359     /* Calculate table index. */
   3360     BCM_IF_ERROR_RETURN(_bcm_esw_src_mod_port_table_index_get(unit, 
   3361         my_modid, port, &index));
   3362 
   3363     /* If port is part of a trunk  - Error */
   3364     SOC_IF_ERROR_RETURN(READ_SOURCE_TRUNK_MAP_TABLEm(unit, MEM_BLOCK_ANY,
   3365                                                      index, &trunk_entry));
   3366     /* Normal port will be encoded as 0 */
   3367     if (soc_SOURCE_TRUNK_MAP_TABLEm_field32_get(unit, &trunk_entry,
   3368                                                 PORT_TYPEf)) {
   3369         return BCM_E_CONFIG;
   3370     }
   3371     hw_index = port;
   3372     rv = _bcm_l2_learn_limit_porttrunk_get(unit, hw_index, flags, limit);
   3373     return rv;
   3374 }
   3375 
   3376 /*
   3377  * Function:
   3378  *      _bcm_l2_learn_limit_trunk_set
   3379  * Purpose:
   3380  *      Set MAC learn limit for a specific port 
   3381  * Parameters:
   3382  *      unit  - BCM unit number
   3383  *      trunk - Trunk identifier
   3384  *      flags - Action bitmask 
   3385  *      limit - Per port limit of MAC addresses to learn 
   3386  *              Negative limit disables the check 
   3387  * Returns:
   3388  *      BCM_E_XXX
   3389  */
   3390 STATIC int
   3391 _bcm_l2_learn_limit_trunk_set(int unit, bcm_trunk_t trunk, uint32 flags,
   3392                               int limit)
   3393 {
   3394     int                                  rv = BCM_E_NONE;
   3395     int                                  hw_index = -1;
   3396     mac_limit_trunk_map_table_entry_t    entry;
   3397     soc_mem_t trunk_mem = TRUNK_GROUPm;
   3398 
   3399     if (soc_feature(unit, soc_feature_fastlag)) {
   3400         trunk_mem = FAST_TRUNK_GROUPm;
   3401     }
   3402 
   3403     if (!SOC_UNIT_VALID(unit)) {
   3404         return BCM_E_UNIT;
   3405     }
   3406 
   3407     if (trunk >= soc_mem_index_count(unit, trunk_mem) || trunk < 0) {
   3408         return BCM_E_PARAM;
   3409     }
   3410 
   3411     if (0 == soc_feature(unit, soc_feature_mac_learn_limit)) {
   3412         return (BCM_E_UNAVAIL);
   3413     }
   3414     hw_index = trunk + PORT_COUNT(unit);
   3415     rv = _bcm_l2_learn_limit_porttrunk_set(unit, hw_index, flags, limit);
   3416     soc_mem_lock(unit, MAC_LIMIT_TRUNK_MAP_TABLEm);
   3417     /* Map port to it's counter */
   3418     rv = READ_MAC_LIMIT_TRUNK_MAP_TABLEm(unit, MEM_BLOCK_ANY, 
   3419                                          trunk, &entry);
   3420     if (BCM_E_NONE == rv) {
   3421         soc_MAC_LIMIT_TRUNK_MAP_TABLEm_field32_set(unit, &entry,
   3422                                                    INDEXf, hw_index);
   3423         rv = WRITE_MAC_LIMIT_TRUNK_MAP_TABLEm(unit, MEM_BLOCK_ALL, 
   3424                                               trunk, &entry);
   3425     }
   3426     soc_mem_unlock(unit, MAC_LIMIT_TRUNK_MAP_TABLEm);
   3427     return rv;
   3428 }
   3429 
   3430 /*
   3431  * Function:
   3432  *      _bcm_l2_learn_limit_trunk_get
   3433  * Purpose:
   3434  *      Get MAC learn limit for a specific port 
   3435  * Parameters:
   3436  *      unit  - BCM unit number
   3437  *      trunk - Trunk identifier
   3438  *      flags - Action bitmask 
   3439  *      limit - Per port limit of MAC addresses to learn 
   3440  *              Negative if limit disabled 
   3441  * Returns:
   3442  *      BCM_E_XXX
   3443  */
   3444 STATIC int
   3445 _bcm_l2_learn_limit_trunk_get(int unit, bcm_trunk_t tid, uint32 *flags,
   3446                               int *limit)
   3447 {
   3448     int rv = BCM_E_NONE;
   3449     int hw_index = -1;
   3450     soc_mem_t trunk_mem = TRUNK_GROUPm;
   3451 
   3452     if (soc_feature(unit, soc_feature_fastlag)) {
   3453         trunk_mem = FAST_TRUNK_GROUPm;
   3454     }
   3455 
   3456     if (!SOC_UNIT_VALID(unit)) {
   3457         return BCM_E_UNIT;
   3458     }
   3459 
   3460     if (tid >= soc_mem_index_count(unit, trunk_mem) || tid < 0) {
   3461         return BCM_E_PARAM;
   3462     }
   3463 
   3464     if (soc_feature(unit, soc_feature_mac_learn_limit)) {
   3465         hw_index = tid + PORT_COUNT(unit);
   3466         rv = _bcm_l2_learn_limit_porttrunk_get(unit, hw_index, flags, limit);
   3467         return rv;
   3468     } 
   3469 
   3470     return BCM_E_UNAVAIL;
   3471 }
   3472 #endif /* BCM_RAPTOR_SUPPORT || BCM_TRIUMPH_SUPPORT */
   3473 /*
   3474  * Function:
   3475  *     bcm_esw_l2_learn_limit_set
   3476  * Description:
   3477  *     Set the L2 MAC learning limit
   3478  * Parameters:
   3479  *     unit        device number
   3480  *     limit       learn limit control info
   3481  *                 limit->flags - qualifiers bits and action bits
   3482  *                 limit->vlan - vlan identifier
   3483  *                 limit->port - port number
   3484  *                 limit->trunk - trunk identifier
   3485  *                 limit->limit - max number of learned entry, -1 for unlimit
   3486  * Return:
   3487  *     BCM_E_XXX
   3488  */
   3489 int
   3490 bcm_esw_l2_learn_limit_set(int unit, bcm_l2_learn_limit_t *limit)
   3491 {
   3492 #if defined(BCM_TRIUMPH_SUPPORT) || defined(BCM_RAPTOR_SUPPORT)
   3493     uint32 type, action, limit_enable, org_limit=0;
   3494 #if defined(BCM_KATANA2_SUPPORT)
   3495     int             id = -1;
   3496     bcm_port_t      _port = -1;
   3497     bcm_trunk_t     _trunk = -1;
   3498     bcm_module_t    _modid = -1;
   3499 #endif
   3500 
   3501 #ifdef BCM_TRIUMPH_SUPPORT
   3502     soc_mem_t trunk_mem = TRUNK_GROUPm;
   3503 
   3504     if (soc_feature(unit, soc_feature_fastlag)) {
   3505         trunk_mem = FAST_TRUNK_GROUPm;
   3506     }
   3507 #endif
   3508 
   3509 #if defined(BCM_TOMAHAWK3_SUPPORT)
   3510     /* Added to handle SDK functions calling esw version,
   3511      * instead of Tomahawk3's version
   3512      */
   3513     if (SOC_IS_TOMAHAWK3(unit)) {
   3514         return bcm_tomahawk3_l2_learn_limit_set(unit, limit);
   3515     }
   3516 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   3517 
   3518     L2_INIT(unit);
   3519 
   3520 #if defined(BCM_TRIUMPH3_SUPPORT)
   3521     if (soc_feature(unit, soc_feature_ism_memory)) {
   3522         return bcm_tr3_l2_learn_limit_set(unit, limit);
   3523     }
   3524 #endif /* BCM_TRIUMPH3_SUPPORT */    
   3525 
   3526     if ((!soc_feature(unit, soc_feature_mac_learn_limit))) {
   3527         return BCM_E_UNAVAIL;
   3528     }
   3529 
   3530     if (!limit) {
   3531         return BCM_E_PARAM;
   3532     }
   3533 
   3534     if (limit->limit > BCM_MAC_LIMIT_MAX){
   3535         return BCM_E_PARAM;
   3536     }
   3537 
   3538     type = limit->flags &
   3539            (BCM_L2_LEARN_LIMIT_SYSTEM | BCM_L2_LEARN_LIMIT_VLAN | 
   3540             BCM_L2_LEARN_LIMIT_PORT | BCM_L2_LEARN_LIMIT_TRUNK);
   3541 
   3542     action = limit->flags & 
   3543              (BCM_L2_LEARN_LIMIT_ACTION_DROP | BCM_L2_LEARN_LIMIT_ACTION_CPU |
   3544               BCM_L2_LEARN_LIMIT_ACTION_PREFER);
   3545 
   3546     if (!type) {
   3547         return BCM_E_PARAM;
   3548     }
   3549 
   3550     if (type != BCM_L2_LEARN_LIMIT_SYSTEM &&
   3551         (action & BCM_L2_LEARN_LIMIT_ACTION_PREFER)) {
   3552         return BCM_E_PARAM;
   3553     }
   3554 
   3555 
   3556     if (type & BCM_L2_LEARN_LIMIT_SYSTEM) {
   3557 #ifdef BCM_TRIUMPH_SUPPORT
   3558         if (SOC_IS_TR_VL(unit)) {
   3559             BCM_IF_ERROR_RETURN
   3560                 (_bcm_tr_l2_learn_limit_system_set(unit, action,
   3561                                                    limit->limit));
   3562         } else
   3563 #endif
   3564         if (soc_feature(unit, soc_feature_system_mac_learn_limit)) {
   3565             BCM_IF_ERROR_RETURN
   3566                 (_bcm_l2_learn_limit_system_set(unit, action, limit->limit));
   3567         } else {
   3568             return BCM_E_UNAVAIL;
   3569         }
   3570     }
   3571 
   3572     if (type & BCM_L2_LEARN_LIMIT_PORT) {
   3573         if (BCM_GPORT_IS_SET(limit->port)) {
   3574 
   3575 #if defined(BCM_KATANA2_SUPPORT)
   3576             if (_BCM_KT2_GPORT_IS_LINKPHY_OR_SUBTAG_SUBPORT_GPORT(unit,
   3577                 limit->port)) {
   3578                 BCM_IF_ERROR_RETURN(
   3579                     _bcm_esw_gport_resolve(unit, limit->port, &_modid, &_port,
   3580                                &_trunk, &id));
   3581                 BCM_IF_ERROR_RETURN(_bcm_kt2_modport_to_pp_port_get(
   3582                     unit, _modid, _port, &(limit->port)));
   3583             } else
   3584 #endif
   3585             {
   3586                 BCM_IF_ERROR_RETURN(
   3587                     bcm_esw_port_local_get(unit, limit->port, &(limit->port)));
   3588             }
   3589         }
   3590 
   3591         if (!SOC_PORT_VALID(unit, limit->port)) {
   3592             return BCM_E_PORT;
   3593         }
   3594             
   3595         /* BCM_L2_LEARN_LIMIT_ACTION_PREFER should be used only in system limit
   3596            and only for Raptor/Raven devices */
   3597         if (limit->flags & BCM_L2_LEARN_LIMIT_ACTION_PREFER) {
   3598             return BCM_E_PARAM;
   3599         }
   3600 
   3601 #ifdef BCM_TRIUMPH_SUPPORT
   3602         if (SOC_IS_TR_VL(unit)) {
   3603             int index;
   3604 
   3605             index = limit->port + soc_mem_index_count(unit, trunk_mem);
   3606             BCM_IF_ERROR_RETURN
   3607                 (_bcm_tr_l2_learn_limit_set(unit, PORT_OR_TRUNK_MAC_LIMITm,
   3608                                             index, action, limit->limit));
   3609         } else
   3610 #endif
   3611         {
   3612             BCM_IF_ERROR_RETURN
   3613                 (_bcm_l2_learn_limit_port_set(unit, limit->port, action,
   3614                                               limit->limit));
   3615         }
   3616     }
   3617 
   3618     if (type & BCM_L2_LEARN_LIMIT_TRUNK) {
   3619         /* BCM_L2_LEARN_LIMIT_ACTION_PREFER should be used only in system limit
   3620            and only for Raptor/Raven devices */
   3621         if (limit->flags & BCM_L2_LEARN_LIMIT_ACTION_PREFER) {
   3622             return BCM_E_PARAM;
   3623         }
   3624 
   3625 #ifdef BCM_TRIUMPH_SUPPORT
   3626         if (SOC_IS_TR_VL(unit)) {
   3627             int index;
   3628 
   3629             if (limit->trunk < 0 ||
   3630                 limit->trunk >= soc_mem_index_count(unit, trunk_mem)) {
   3631                 return BCM_E_PARAM;
   3632             }
   3633             index = limit->trunk;
   3634             BCM_IF_ERROR_RETURN
   3635                 (_bcm_tr_l2_learn_limit_set(unit, PORT_OR_TRUNK_MAC_LIMITm,
   3636                                             index, action, limit->limit));
   3637         } else
   3638 #endif
   3639         {
   3640             BCM_IF_ERROR_RETURN
   3641                 (_bcm_l2_learn_limit_trunk_set(unit, limit->trunk, action,
   3642                                                limit->limit));
   3643         }
   3644     }
   3645 
   3646 #ifdef BCM_TRIUMPH_SUPPORT
   3647     if (type & BCM_L2_LEARN_LIMIT_VLAN) {
   3648         /* BCM_L2_LEARN_LIMIT_ACTION_PREFER should be used only in system limit
   3649            and only for Raptor/Raven devices */
   3650         if (limit->flags & BCM_L2_LEARN_LIMIT_ACTION_PREFER) {
   3651             return BCM_E_PARAM;
   3652         }
   3653 
   3654         if (SOC_IS_TR_VL(unit)) {
   3655             int index, vfi;
   3656 
   3657             if (_BCM_VPN_VFI_IS_SET(limit->vlan)) {
   3658                 _BCM_VPN_GET(vfi, _BCM_VPN_TYPE_VFI, limit->vlan);
   3659                 if (vfi >= soc_mem_index_count(unit, VFIm)) {
   3660                     return BCM_E_PARAM;
   3661                 }
   3662                 index = vfi + soc_mem_index_count(unit, VLAN_TABm);
   3663             } else {
   3664                 if (limit->vlan >= soc_mem_index_count(unit, VLAN_TABm)) {
   3665                     return BCM_E_PARAM;
   3666                 }
   3667                 index = limit->vlan;
   3668             }
   3669             BCM_IF_ERROR_RETURN
   3670                 (_bcm_tr_l2_learn_limit_set(unit, VLAN_OR_VFI_MAC_LIMITm,
   3671                                             index, action, limit->limit));
   3672         }
   3673     }
   3674 
   3675     if (SOC_IS_TR_VL(unit)) {
   3676         return BCM_E_NONE;
   3677     }
   3678 #endif
   3679 
   3680     /* Enable the MAC learn limit feature after configuring the indexes */
   3681     /* Negative limit disables the check */
   3682     if (limit->limit < 0) {
   3683         BCM_IF_ERROR_RETURN(READ_MAC_LIMIT_ENABLEr(unit, &limit_enable));
   3684         soc_reg_field_set(unit, MAC_LIMIT_ENABLEr, &limit_enable, 
   3685                           ENABLEf, 0);
   3686         BCM_IF_ERROR_RETURN(WRITE_MAC_LIMIT_ENABLEr(unit, limit_enable));
   3687     } else {
   3688         BCM_IF_ERROR_RETURN(READ_MAC_LIMIT_ENABLEr(unit, &limit_enable));
   3689         org_limit = soc_reg_field_get(unit, MAC_LIMIT_ENABLEr, limit_enable,
   3690                                       ENABLEf);
   3691         if (!org_limit) {
   3692             soc_reg_field_set(unit, MAC_LIMIT_ENABLEr, &limit_enable, 
   3693                               ENABLEf, 1);
   3694             BCM_IF_ERROR_RETURN(WRITE_MAC_LIMIT_ENABLEr(unit, limit_enable));
   3695         }
   3696     }
   3697     return BCM_E_NONE;
   3698 #else /* BCM_TRIUMPH_SUPPORT || BCM_RAPTOR_SUPPORT */
   3699     return (BCM_E_UNAVAIL);
   3700 #endif /* BCM_TRIUMPH_SUPPORT || BCM_RAPTOR_SUPPORT */
   3701 }
   3702 
   3703 /*
   3704  * Function:
   3705  *     bcm_esw_l2_learn_limit_get
   3706  * Description:
   3707  *     Get the L2 MAC learning limit
   3708  * Parameters:
   3709  *     unit        device number
   3710  *     limit       learn limit control info
   3711  *                 limit->flags - qualifiers bits and action bits
   3712  *                 limit->vlan - vlan identifier
   3713  *                 limit->port - port number
   3714  *                 limit->trunk - trunk identifier
   3715  *                 limit->limit - max number of learned entry, -1 for unlimit
   3716  * Return:
   3717  *     BCM_E_XXX
   3718  */
   3719 int
   3720 bcm_esw_l2_learn_limit_get(int unit, bcm_l2_learn_limit_t *limit)
   3721 {
   3722 #if defined(BCM_TRIUMPH_SUPPORT) || defined(BCM_RAPTOR_SUPPORT)
   3723     int rv;
   3724     uint32 type, action;
   3725     int max;
   3726 #if defined(BCM_KATANA2_SUPPORT) || defined(BCM_HGPROXY_COE_SUPPORT)
   3727     int             id = -1;
   3728     bcm_port_t      _port = -1;
   3729     bcm_trunk_t     _trunk = -1;
   3730     bcm_module_t    _modid = -1;
   3731 #endif
   3732 
   3733 #ifdef BCM_TRIUMPH_SUPPORT
   3734     soc_mem_t   trunk_mem = TRUNK_GROUPm;
   3735 
   3736     if (soc_feature(unit, soc_feature_fastlag)) {
   3737         trunk_mem = FAST_TRUNK_GROUPm;
   3738     }
   3739 #endif
   3740 
   3741 #if defined(BCM_TOMAHAWK3_SUPPORT)
   3742     /* Added to handle SDK functions calling esw version,
   3743      * instead of Tomahawk3's version
   3744      */
   3745     if (SOC_IS_TOMAHAWK3(unit)) {
   3746         return bcm_tomahawk3_l2_learn_limit_get(unit, limit);
   3747     }
   3748 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   3749 
   3750     L2_INIT(unit);
   3751 
   3752 #if defined(BCM_TRIUMPH3_SUPPORT)
   3753     if (soc_feature(unit, soc_feature_ism_memory)) {
   3754         return bcm_tr3_l2_learn_limit_get(unit, limit);
   3755     }
   3756 #endif /* BCM_TRIUMPH3_SUPPORT */    
   3757 
   3758     if (!soc_feature(unit, soc_feature_mac_learn_limit)) {
   3759         return BCM_E_UNAVAIL;
   3760     }
   3761 
   3762     if (!limit) {
   3763         return BCM_E_PARAM;
   3764     }
   3765 
   3766     type = limit->flags &
   3767            (BCM_L2_LEARN_LIMIT_SYSTEM | BCM_L2_LEARN_LIMIT_VLAN | 
   3768             BCM_L2_LEARN_LIMIT_PORT | BCM_L2_LEARN_LIMIT_TRUNK);
   3769     action = 0;
   3770     max = 0;
   3771 
   3772     rv = BCM_E_UNAVAIL;
   3773     switch (type) {
   3774     case BCM_L2_LEARN_LIMIT_SYSTEM:
   3775 #ifdef BCM_TRIUMPH_SUPPORT
   3776       if (SOC_IS_TR_VL(unit)) {
   3777             return _bcm_tr_l2_learn_limit_system_get(unit, &limit->flags,
   3778                                                      &limit->limit);
   3779         }
   3780 #endif
   3781       if (soc_feature(unit, soc_feature_system_mac_learn_limit)) {
   3782         rv = _bcm_l2_learn_limit_system_get(unit, &action, &max);
   3783       } 
   3784       break;
   3785 
   3786     case BCM_L2_LEARN_LIMIT_PORT:
   3787         if (BCM_GPORT_IS_SET(limit->port)) {
   3788 
   3789 #if defined(BCM_HGPROXY_COE_SUPPORT)
   3790             if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
   3791                 _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, limit->port)) {
   3792 
   3793                 BCM_IF_ERROR_RETURN(
   3794                     _bcm_esw_gport_resolve(unit, limit->port, &_modid, &_port,
   3795                                &_trunk, &id));
   3796 
   3797                 BCM_IF_ERROR_RETURN(_bcmi_coe_subport_physical_port_get(unit,
   3798                                         limit->port, &(limit->port)));
   3799             } else 
   3800 #endif
   3801 #if defined(BCM_KATANA2_SUPPORT)
   3802             if (_BCM_KT2_GPORT_IS_LINKPHY_OR_SUBTAG_SUBPORT_GPORT(unit,
   3803                 limit->port)) {
   3804                 BCM_IF_ERROR_RETURN(
   3805                     _bcm_esw_gport_resolve(unit, limit->port, &_modid, &_port,
   3806                                &_trunk, &id));
   3807                 BCM_IF_ERROR_RETURN(_bcm_kt2_modport_to_pp_port_get(
   3808                     unit, _modid, _port, &(limit->port)));
   3809             } else
   3810 #endif
   3811             {
   3812                 BCM_IF_ERROR_RETURN(
   3813                     bcm_esw_port_local_get(unit, limit->port, &(limit->port)));
   3814             }
   3815         }
   3816 
   3817         if (!SOC_PORT_VALID(unit, limit->port)) {
   3818             return BCM_E_PORT;
   3819         }
   3820 #ifdef BCM_TRIUMPH_SUPPORT
   3821         if (SOC_IS_TR_VL(unit)) {
   3822             int index;
   3823             index = limit->port + soc_mem_index_count(unit, trunk_mem);
   3824             return _bcm_tr_l2_learn_limit_get(unit, PORT_OR_TRUNK_MAC_LIMITm,
   3825                                               index, &limit->flags,
   3826                                               &limit->limit);
   3827         }
   3828 #endif
   3829         rv = _bcm_l2_learn_limit_port_get(unit, limit->port, &action, &max);
   3830         break;
   3831 
   3832     case BCM_L2_LEARN_LIMIT_TRUNK:
   3833 #ifdef BCM_TRIUMPH_SUPPORT
   3834         if (SOC_IS_TR_VL(unit)) {
   3835             int index;
   3836 
   3837             if (limit->trunk < 0 ||
   3838                 limit->trunk >= soc_mem_index_count(unit, trunk_mem)) {
   3839                 return BCM_E_PARAM;
   3840             }
   3841             index = limit->trunk;
   3842             return _bcm_tr_l2_learn_limit_get(unit, PORT_OR_TRUNK_MAC_LIMITm,
   3843                                               index, &limit->flags,
   3844                                               &limit->limit);
   3845         }
   3846 #endif
   3847         rv = _bcm_l2_learn_limit_trunk_get(unit, limit->trunk, &action, &max);
   3848         break;
   3849 
   3850     case BCM_L2_LEARN_LIMIT_VLAN:
   3851 #ifdef BCM_TRIUMPH_SUPPORT
   3852         if (SOC_IS_TR_VL(unit)) {
   3853             int index, vfi;
   3854 
   3855             if (_BCM_VPN_VFI_IS_SET(limit->vlan)) {
   3856                 _BCM_VPN_GET(vfi, _BCM_VPN_TYPE_VFI, limit->vlan);
   3857                 if (vfi >= soc_mem_index_count(unit, VFIm)) {
   3858                     return BCM_E_PARAM;
   3859                 }
   3860                 index = vfi + soc_mem_index_count(unit, VLAN_TABm);
   3861             } else {
   3862                 if (limit->vlan >= soc_mem_index_count(unit, VLAN_TABm)) {
   3863                     return BCM_E_PARAM;
   3864                 }
   3865                 index = limit->vlan;
   3866             }
   3867             return _bcm_tr_l2_learn_limit_get(unit, VLAN_OR_VFI_MAC_LIMITm,
   3868                                               index, &limit->flags,
   3869                                               &limit->limit);
   3870         }
   3871 #endif
   3872         break;
   3873 
   3874     default:
   3875         return BCM_E_PARAM;
   3876     }
   3877 
   3878     if (rv == BCM_E_NONE) {
   3879         limit->flags |= action;
   3880         limit->limit = max;
   3881     }
   3882     return rv;
   3883 #else /* BCM_TRIUMPH_SUPPORT || BCM_RAPTOR_SUPPORT */
   3884     return (BCM_E_UNAVAIL);
   3885 #endif /* BCM_TRIUMPH_SUPPORT || BCM_RAPTOR_SUPPORT */
   3886 }
   3887 
   3888 /*
   3889  * Function:
   3890  *     bcm_esw_l2_learn_class_set
   3891  * Description:
   3892  *     To set the attributes of L2 learning class
   3893  * Parameters:
   3894  *     unit        device number
   3895  *     lclass      learning class id (0 - 3)
   3896  *     lclass_prio learning class priority (0 - 3, 3 is the highest)
   3897  *     flags       flags (BCM_L2_LEARN_CLASS_*)
   3898  * Return:
   3899  *     BCM_E_XXX
   3900  * Note:
   3901  *     This feature is disabled by default (see bcmPortControlLearnClassEnable).
   3902  *     By default, each learning class is assigned priority 0 (lowest)
   3903  *     and the attribute, BCM_L2_LEARN_CLASS_MOVE, is not set. By default,
   3904  *     each port is assigned to learning class 0.
   3905  */
   3906 int
   3907 bcm_esw_l2_learn_class_set(int unit, int lclass, int lclass_prio, uint32 flags)
   3908 {
   3909 #if defined(BCM_TRX_SUPPORT)
   3910     uint32 data;
   3911 
   3912 #if defined(BCM_TOMAHAWK3_SUPPORT)
   3913     /* Added to handle SDK functions calling esw version,
   3914      * instead of Tomahawk3's version
   3915      */
   3916     if (SOC_IS_TOMAHAWK3(unit)) {
   3917         return bcm_tomahawk3_l2_learn_class_set(unit, lclass, lclass_prio,
   3918                                                 flags);
   3919     }
   3920 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   3921 
   3922     L2_INIT(unit);
   3923 
   3924 #if defined(BCM_TRIUMPH3_SUPPORT)
   3925     if (soc_feature(unit, soc_feature_ism_memory)) {
   3926         return bcm_tr3_l2_learn_class_set(unit, lclass, lclass_prio, flags);
   3927     }
   3928 #endif /* BCM_TRIUMPH3_SUPPORT */    
   3929 
   3930     if (!soc_feature(unit, soc_feature_class_based_learning)) {
   3931         return (BCM_E_UNAVAIL);
   3932     }
   3933 
   3934     if (lclass < 0 || lclass >= SOC_REG_NUMELS(unit, CBL_ATTRIBUTEr) ||
   3935         lclass_prio < 0 ||
   3936         lclass_prio >= (1 << soc_reg_field_length(unit, CBL_ATTRIBUTEr,
   3937                                                   PORT_LEARNING_PRIORITYf))) {
   3938         return (BCM_E_PARAM);
   3939     }
   3940 
   3941     BCM_IF_ERROR_RETURN(READ_CBL_ATTRIBUTEr(unit, lclass, &data));
   3942     soc_reg_field_set(unit, CBL_ATTRIBUTEr, &data, PORT_LEARNING_PRIORITYf,
   3943                       lclass_prio);
   3944     soc_reg_field_set(unit, CBL_ATTRIBUTEr, &data, ALLOW_MOVE_IN_CLASSf,
   3945                       flags & BCM_L2_LEARN_CLASS_MOVE ? 1 : 0);
   3946     BCM_IF_ERROR_RETURN(WRITE_CBL_ATTRIBUTEr(unit, lclass, data));
   3947 
   3948     return SOC_E_NONE;
   3949 #else /* BCM_TRIUMPH_SUPPORT */
   3950     return (BCM_E_UNAVAIL);
   3951 #endif /* BCM_TRIUMPH_SUPPORT */
   3952 }
   3953 /*
   3954  * Function:
   3955  *     bcm_esw_l2_learn_class_get
   3956  * Description:
   3957  *     To get the attributes of L2 learning class
   3958  * Parameters:
   3959  *     unit        device number
   3960  *     lclass      learning class id (0 - 3)
   3961  *     lclass_prio learning class priority (0 - 3, 3 is the highest)
   3962  *     flags       flags (BCM_L2_LEARN_CLASS_*)
   3963  * Return:
   3964  *     BCM_E_XXX
   3965  */
   3966 int
   3967 bcm_esw_l2_learn_class_get(int unit, int lclass, int *lclass_prio, uint32 *flags)
   3968 {
   3969 #if defined(BCM_TRX_SUPPORT)
   3970     uint32 data;
   3971 
   3972 #if defined(BCM_TOMAHAWK3_SUPPORT)
   3973     /* Added to handle SDK functions calling esw version,
   3974      * instead of Tomahawk3's version
   3975      */
   3976     if (SOC_IS_TOMAHAWK3(unit)) {
   3977         return bcm_tomahawk3_l2_learn_class_get(unit, lclass, lclass_prio,
   3978                                                 flags);
   3979     }
   3980 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   3981 
   3982     L2_INIT(unit);
   3983 
   3984 #if defined(BCM_TRIUMPH3_SUPPORT)
   3985     if (soc_feature(unit, soc_feature_ism_memory)) {
   3986         return bcm_tr3_l2_learn_class_get(unit, lclass, lclass_prio, flags);
   3987     }
   3988 #endif /* BCM_TRIUMPH3_SUPPORT */    
   3989 
   3990     if (!soc_feature(unit, soc_feature_class_based_learning)) {
   3991         return (BCM_E_UNAVAIL);
   3992     }
   3993 
   3994     if (lclass < 0 || lclass >= SOC_REG_NUMELS(unit, CBL_ATTRIBUTEr) ||
   3995         lclass_prio == NULL || flags == NULL) {
   3996         return (BCM_E_PARAM);
   3997     }
   3998 
   3999     BCM_IF_ERROR_RETURN(READ_CBL_ATTRIBUTEr(unit, lclass, &data));
   4000     *lclass_prio = soc_reg_field_get(unit, CBL_ATTRIBUTEr, data,
   4001                                      PORT_LEARNING_PRIORITYf);
   4002     *flags = 0;
   4003     if (soc_reg_field_get(unit, CBL_ATTRIBUTEr, data, ALLOW_MOVE_IN_CLASSf)) {
   4004         *flags |= BCM_L2_LEARN_CLASS_MOVE;
   4005     }
   4006 
   4007     return (BCM_E_NONE);
   4008 #else /* BCM_TRX_SUPPORT */
   4009     return (BCM_E_UNAVAIL);
   4010 #endif /* BCM_TRX_SUPPORT */
   4011 }
   4012 
   4013 /*
   4014  * Function:
   4015  *     bcm_esw_l2_learn_port_class_set
   4016  * Description:
   4017  *     To set the L2 learning class of a port
   4018  * Parameters:
   4019  *     unit        device number
   4020  *     port        Ingress generic port
   4021  *     lclass      learning class id (0 - 3)
   4022  * Return:
   4023  *     BCM_E_XXX
   4024  * Note:
   4025  *     This feature is disabled by default (see bcmPortControlLearnClassEnable).
   4026  *     By default, each port is assigned to learning class 0.
   4027  */
   4028 int
   4029 bcm_esw_l2_learn_port_class_set(int unit, bcm_gport_t port, int lclass)
   4030 {
   4031 #if defined(BCM_TRX_SUPPORT)
   4032     bcm_module_t module;
   4033     bcm_port_t local_port;
   4034     bcm_trunk_t trunk;
   4035     int id;
   4036 
   4037 #if defined(BCM_TOMAHAWK3_SUPPORT)
   4038     /* Added to handle SDK functions calling this function directly.
   4039      * Class based learning is not supported on TH3
   4040      */
   4041     if (SOC_IS_TOMAHAWK3(unit)) {
   4042         return BCM_E_UNAVAIL;
   4043     }
   4044 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   4045 
   4046     L2_INIT(unit);
   4047 
   4048 #if defined(BCM_TRIUMPH3_SUPPORT)
   4049     if (soc_feature(unit, soc_feature_ism_memory)) {
   4050         return bcm_tr3_l2_learn_port_class_set(unit, port, lclass);
   4051     }
   4052 #endif /* BCM_TRIUMPH3_SUPPORT */    
   4053 
   4054     if (!soc_feature(unit, soc_feature_class_based_learning)) {
   4055         return BCM_E_UNAVAIL;
   4056     }
   4057 
   4058     BCM_L2_LEARN_CLASSID_VALID(lclass);
   4059 
   4060     BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, port, &module,
   4061                                                &local_port, &trunk, &id));
   4062 
   4063     if (soc_feature(unit, soc_feature_linkphy_coe) ||
   4064         soc_feature(unit, soc_feature_subtag_coe)  ||
   4065         soc_feature(unit, soc_feature_hgproxy_subtag_coe)) {
   4066 
   4067 #if defined(BCM_HGPROXY_COE_SUPPORT)
   4068         if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
   4069             _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port)) {
   4070             id = -1;
   4071         }
   4072 #endif
   4073 #if defined(BCM_KATANA2_SUPPORT)
   4074         if (_BCM_KT2_GPORT_IS_LINKPHY_OR_SUBTAG_SUBPORT_GPORT(unit, port)) {
   4075             id = -1;
   4076         }
   4077 #endif
   4078     }
   4079     if (id != -1) {
   4080         if (!BCM_GPORT_IS_MPLS_PORT(port) &&
   4081             !BCM_GPORT_IS_SUBPORT_GROUP(port) &&
   4082             !BCM_GPORT_IS_SUBPORT_PORT(port) &&
   4083             !BCM_GPORT_IS_MIM_PORT(port) &&
   4084             !BCM_GPORT_IS_VLAN_PORT(port) &&
   4085             !BCM_GPORT_IS_WLAN_PORT(port) &&
   4086             !BCM_GPORT_IS_TRILL_PORT(port) &&
   4087             !BCM_GPORT_IS_NIV_PORT(port) &&
   4088             !BCM_GPORT_IS_L2GRE_PORT(port) &&
   4089             !BCM_GPORT_IS_VXLAN_PORT(port) &&
   4090             !BCM_GPORT_IS_EXTENDER_PORT(port)) {
   4091             return BCM_E_PARAM;
   4092         }
   4093         return soc_mem_field32_modify(unit, PORT_CBL_TABLEm, id,
   4094                                       VIRTUAL_PORT_LEARNING_CLASSf, lclass);
   4095     } else if (trunk != -1) {
   4096         return soc_mem_field32_modify(unit, TRUNK_CBL_TABLEm, trunk,
   4097                                       PORT_LEARNING_CLASSf, lclass);
   4098     } else if (!soc_mem_is_valid(unit, PORT_CBL_TABLE_MODBASEm)) {
   4099         return soc_mem_field32_modify(unit, PORT_CBL_TABLEm,
   4100                                       module * (SOC_PORT_ADDR_MAX(unit) + 1) +
   4101                                       local_port,
   4102                                       PORT_LEARNING_CLASSf, lclass);
   4103     }
   4104 #ifdef BCM_TRIDENT_SUPPORT
   4105     else {
   4106         soc_profile_mem_t *profile;
   4107         port_cbl_table_modbase_entry_t base_entry;
   4108         port_cbl_table_entry_t cbl_entries[256];
   4109         void *entries[1];
   4110         uint32 old_index, index;
   4111         int rv;
   4112 
   4113         profile = _bcm_l2_port_cbl_profile[unit];
   4114         entries[0] = &cbl_entries;
   4115 
   4116         soc_mem_lock(unit, PORT_CBL_TABLE_MODBASEm);
   4117 
   4118         rv = soc_mem_read(unit, PORT_CBL_TABLE_MODBASEm, MEM_BLOCK_ALL, module,
   4119                           &base_entry);
   4120         if (SOC_FAILURE(rv)) {
   4121             soc_mem_unlock(unit, PORT_CBL_TABLE_MODBASEm);
   4122             return rv;
   4123         }
   4124         old_index = soc_mem_field32_get(unit, PORT_CBL_TABLE_MODBASEm,
   4125                                         &base_entry, BASEf);
   4126         rv = soc_profile_mem_get(unit, profile, old_index,
   4127                                  SOC_PORT_ADDR_MAX(unit) + 1, entries);
   4128         if (BCM_FAILURE(rv)) {
   4129             soc_mem_unlock(unit, PORT_CBL_TABLE_MODBASEm);
   4130             return rv;
   4131         }
   4132         soc_mem_field32_set(unit, PORT_CBL_TABLEm, &cbl_entries[local_port],
   4133                             PORT_LEARNING_CLASSf, lclass);
   4134         rv = soc_profile_mem_add(unit, profile, entries,
   4135                                  SOC_PORT_ADDR_MAX(unit) + 1, &index);
   4136         if (BCM_FAILURE(rv)) {
   4137             soc_mem_unlock(unit, PORT_CBL_TABLE_MODBASEm);
   4138             return rv;
   4139         }
   4140         rv = soc_mem_field32_modify(unit, PORT_CBL_TABLE_MODBASEm, module,
   4141                                     BASEf, index);
   4142         if (BCM_FAILURE(rv)) {
   4143             soc_mem_unlock(unit, PORT_CBL_TABLE_MODBASEm);
   4144             return rv;
   4145         }
   4146         rv = soc_profile_mem_delete(unit, profile, old_index);
   4147 
   4148         soc_mem_unlock(unit, PORT_CBL_TABLE_MODBASEm);
   4149 
   4150         return rv;
   4151     }
   4152 #endif /* BCM_TRIDENT_SUPPORT */
   4153     return BCM_E_NONE;
   4154 #else /* BCM_TRX_SUPPORT */
   4155     return (BCM_E_UNAVAIL);
   4156 #endif /* BCM_TRX_SUPPORT */
   4157 }
   4158 
   4159 /*
   4160  * Function:
   4161  *     bcm_esw_l2_learn_port_class_get
   4162  * Description:
   4163  *     To get the L2 learning class of a port
   4164  * Parameters:
   4165  *     unit        device number
   4166  *     port        Ingress generic port
   4167  *     lclass      learning class id (0 - 3)
   4168  * Return:
   4169  *     BCM_E_XXX
   4170  */
   4171 int
   4172 bcm_esw_l2_learn_port_class_get(int unit, bcm_gport_t port, int *lclass)
   4173 {
   4174 #if defined(BCM_TRX_SUPPORT)
   4175     bcm_module_t module;
   4176     bcm_port_t local_port;
   4177     bcm_trunk_t trunk;
   4178     int id;
   4179     port_cbl_table_entry_t port_entry;
   4180     trunk_cbl_table_entry_t trunk_entry;
   4181 
   4182 #if defined(BCM_TOMAHAWK3_SUPPORT)
   4183     /* Added to handle SDK functions calling this function directly. Class based
   4184      * learning is not supported on TH3
   4185      */
   4186     if (SOC_IS_TOMAHAWK3(unit)) {
   4187         return BCM_E_UNAVAIL;
   4188     }
   4189 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   4190 
   4191     L2_INIT(unit);
   4192 
   4193 #if defined(BCM_TRIUMPH3_SUPPORT)
   4194     if (soc_feature(unit, soc_feature_ism_memory)) {
   4195         return bcm_tr3_l2_learn_port_class_get(unit, port, lclass);
   4196     }
   4197 #endif /* BCM_TRIUMPH3_SUPPORT */    
   4198 
   4199     if (!soc_feature(unit, soc_feature_class_based_learning)) {
   4200         return BCM_E_UNAVAIL;
   4201     }
   4202 
   4203     if (lclass == NULL) {
   4204         return BCM_E_PARAM;
   4205     }
   4206     BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, port, &module,
   4207                                                &local_port, &trunk, &id));
   4208 
   4209     if (soc_feature(unit, soc_feature_linkphy_coe) ||
   4210         soc_feature(unit, soc_feature_subtag_coe)  ||
   4211         soc_feature(unit, soc_feature_hgproxy_subtag_coe)) {
   4212 
   4213 #if defined(BCM_HGPROXY_COE_SUPPORT)
   4214         if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
   4215             _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port)) {
   4216             id = -1;
   4217         }
   4218 #endif
   4219 #if defined(BCM_KATANA2_SUPPORT)
   4220         if (_BCM_KT2_GPORT_IS_LINKPHY_OR_SUBTAG_SUBPORT_GPORT(unit, port)) {
   4221             id = -1;
   4222         }
   4223 #endif
   4224     }
   4225     if (id != -1) {
   4226         if (!BCM_GPORT_IS_MPLS_PORT(port) &&
   4227             !BCM_GPORT_IS_SUBPORT_GROUP(port) &&
   4228             !BCM_GPORT_IS_SUBPORT_PORT(port) &&
   4229             !BCM_GPORT_IS_MIM_PORT(port) &&
   4230             !BCM_GPORT_IS_VLAN_PORT(port) &&
   4231             !BCM_GPORT_IS_WLAN_PORT(port) &&
   4232             !BCM_GPORT_IS_TRILL_PORT(port) &&
   4233             !BCM_GPORT_IS_NIV_PORT(port) &&
   4234             !BCM_GPORT_IS_L2GRE_PORT(port) &&
   4235             !BCM_GPORT_IS_VXLAN_PORT(port) &&
   4236             !BCM_GPORT_IS_EXTENDER_PORT(port)) {
   4237             return BCM_E_PARAM;
   4238         }
   4239         BCM_IF_ERROR_RETURN
   4240             (READ_PORT_CBL_TABLEm(unit, MEM_BLOCK_ALL, id, &port_entry));
   4241         *lclass = soc_mem_field32_get(unit, PORT_CBL_TABLEm, &port_entry,
   4242                                       VIRTUAL_PORT_LEARNING_CLASSf);
   4243     } else if (trunk != -1) {
   4244         BCM_IF_ERROR_RETURN
   4245             (READ_TRUNK_CBL_TABLEm(unit, MEM_BLOCK_ALL, trunk, &trunk_entry));
   4246         *lclass = soc_mem_field32_get(unit, TRUNK_CBL_TABLEm, &trunk_entry,
   4247                                       PORT_LEARNING_CLASSf);
   4248     } else if (!soc_mem_is_valid(unit, PORT_CBL_TABLE_MODBASEm)) {
   4249         BCM_IF_ERROR_RETURN
   4250             (READ_PORT_CBL_TABLEm(unit, MEM_BLOCK_ALL,
   4251                                   module * (SOC_PORT_ADDR_MAX(unit) + 1) +
   4252                                   local_port, &port_entry));
   4253         *lclass = soc_mem_field32_get(unit, PORT_CBL_TABLEm, &port_entry,
   4254                                       PORT_LEARNING_CLASSf);
   4255     }
   4256 #ifdef BCM_TRIDENT_SUPPORT
   4257     else {
   4258         soc_profile_mem_t *profile;
   4259         port_cbl_table_modbase_entry_t base_entry;
   4260         port_cbl_table_entry_t cbl_entries[256];
   4261         void *entries[1];
   4262         uint32 index;
   4263 
   4264         profile = _bcm_l2_port_cbl_profile[unit];
   4265         entries[0] = &cbl_entries;
   4266 
   4267         BCM_IF_ERROR_RETURN
   4268             (soc_mem_read(unit, PORT_CBL_TABLE_MODBASEm, MEM_BLOCK_ALL, module,
   4269                           &base_entry));
   4270         index = soc_mem_field32_get(unit, PORT_CBL_TABLE_MODBASEm, &base_entry,
   4271                                     BASEf);
   4272 
   4273         BCM_IF_ERROR_RETURN
   4274             (soc_profile_mem_get(unit, profile, index,
   4275                                  SOC_PORT_ADDR_MAX(unit) + 1, entries));
   4276         *lclass = soc_mem_field32_get(unit, PORT_CBL_TABLEm,
   4277                                       &cbl_entries[local_port],
   4278                                       PORT_LEARNING_CLASSf);
   4279     }
   4280 #endif /* BCM_TRIDENT_SUPPORT */
   4281 
   4282     return BCM_E_NONE;
   4283 #else /* BCM_TRX_SUPPORT */
   4284     return (BCM_E_UNAVAIL);
   4285 #endif /* BCM_TRX_SUPPORT */
   4286 }
   4287 
   4288 #ifdef BCM_HURRICANE3_SUPPORT
   4289 /*
   4290  * Function:
   4291  *     _bcm_esw_l2_learn_stat_set
   4292  * Description:
   4293  *     To set or clear the specified L2 hash counter to the indicated value.
   4294  * Parameters:
   4295  *      unit - (IN) Unit number.
   4296  *      learn_stat - (IN) Pointer to the L2 learned statistic structure.
   4297  * Return:
   4298  *     BCM_E_XXX
   4299  */
   4300 STATIC int
   4301 _bcm_esw_l2_learn_stat_set(int unit, bcm_l2_learn_stat_t *learn_stat)
   4302 {
   4303     uint32 val=0;
   4304     soc_field_t learn_field;
   4305     soc_reg_t learn_reg;
   4306 
   4307     if (learn_stat == NULL) {
   4308         return (BCM_E_PARAM);
   4309     }
   4310 
   4311     switch(learn_stat->type) {
   4312         case bcmL2LearnStatL2TableLearned:
   4313             if (SOC_REG_IS_VALID(unit, L2_ENTRY_LEARNED_CNTr)) {
   4314                 learn_reg = L2_ENTRY_LEARNED_CNTr;
   4315                 learn_field = COUNTERf;
   4316             } else {
   4317                 return (BCM_E_UNAVAIL);
   4318             }
   4319             break;
   4320         case bcmL2LearnStatOverflowPoolLearned:
   4321             if (SOC_REG_IS_VALID(unit, L2_128_OVF_LEARNED_CNTr)) {
   4322                 learn_reg = L2_128_OVF_LEARNED_CNTr;
   4323                 learn_field = COUNTERf;
   4324             } else {
   4325                 return (BCM_E_UNAVAIL);
   4326             }
   4327             break;
   4328         case bcmL2LearnStatHashCollisions:
   4329             if (SOC_REG_IS_VALID(unit, L2_ENTRY_COLLISION_CNTr)) {
   4330                 learn_reg = L2_ENTRY_COLLISION_CNTr;
   4331                 learn_field = COUNTERf;
   4332             } else {
   4333                 return (BCM_E_UNAVAIL);
   4334             }
   4335             break;
   4336         default:
   4337             return (BCM_E_PARAM);
   4338     }
   4339 
   4340      BCM_IF_ERROR_RETURN(soc_reg32_get
   4341          (unit, learn_reg, REG_PORT_ANY, 0, &val));
   4342      soc_reg_field_set(unit, learn_reg, &val, learn_field, learn_stat->value);
   4343      BCM_IF_ERROR_RETURN(soc_reg32_set
   4344          (unit, learn_reg, REG_PORT_ANY, 0, val));
   4345 
   4346     return (BCM_E_NONE);
   4347 }
   4348 
   4349 /*
   4350  * Function:
   4351  *     _bcm_esw_l2_learn_stat_get
   4352  * Description:
   4353  *     To get the statistic of the specified L2 hash counter from chip.
   4354  * Parameters:
   4355  *      unit - (IN) Unit number.
   4356  *      learn_stat - (INOUT) Pointer to the L2 learned statistic structure.
   4357  * Return:
   4358  *     BCM_E_XXX
   4359  */
   4360 STATIC int
   4361 _bcm_esw_l2_learn_stat_get(int unit, bcm_l2_learn_stat_t *learn_stat)
   4362 {
   4363     uint32 val=0;
   4364     soc_field_t learn_field;
   4365     soc_reg_t learn_reg;
   4366 
   4367     if (learn_stat == NULL) {
   4368         return (BCM_E_PARAM);
   4369     }
   4370 
   4371     switch(learn_stat->type) {
   4372         case bcmL2LearnStatL2TableLearned:
   4373             if (SOC_REG_IS_VALID(unit, L2_ENTRY_LEARNED_CNTr)) {
   4374                 learn_reg = L2_ENTRY_LEARNED_CNTr;
   4375                 learn_field = COUNTERf;
   4376             } else {
   4377                 return (BCM_E_UNAVAIL);
   4378             }
   4379             break;
   4380         case bcmL2LearnStatOverflowPoolLearned:
   4381             if (SOC_REG_IS_VALID(unit, L2_128_OVF_LEARNED_CNTr)) {
   4382                 learn_reg = L2_128_OVF_LEARNED_CNTr;
   4383                 learn_field = COUNTERf;
   4384             } else {
   4385                 return (BCM_E_UNAVAIL);
   4386             }
   4387             break;
   4388         case bcmL2LearnStatHashCollisions:
   4389             if (SOC_REG_IS_VALID(unit, L2_ENTRY_COLLISION_CNTr)) {
   4390                 learn_reg = L2_ENTRY_COLLISION_CNTr;
   4391                 learn_field = COUNTERf;
   4392             } else {
   4393                 return (BCM_E_UNAVAIL);
   4394             }
   4395             break;
   4396         default:
   4397             return (BCM_E_PARAM);
   4398     }
   4399 
   4400      BCM_IF_ERROR_RETURN(soc_reg32_get
   4401          (unit, learn_reg, REG_PORT_ANY, 0, &val));
   4402      learn_stat->value = soc_reg_field_get(unit, learn_reg, val, learn_field);
   4403 
   4404     return (BCM_E_NONE);
   4405 }
   4406 #endif /* BCM_HURRICANE3_SUPPORT */
   4407 
   4408 /*
   4409  * Function:
   4410  *     bcm_esw_l2_learn_stat_set
   4411  * Description:
   4412  *     To set or clear the specified L2 hash counter to the indicated value.
   4413  * Parameters:
   4414  *      unit - (IN) Unit number.
   4415  *      learn_stat - (IN) Pointer to the L2 learned statistic structure.
   4416  * Return:
   4417  *     BCM_E_XXX
   4418  * Note:
   4419  *     The purposes of these counters are used to monitor the L2 hash condition.
   4420  *     When the counter counts to 32'hffff_ffff (maximum value), it will keep this value till
   4421  *     software clear it. Currently these L2 hash counters are system-wise.
   4422  */
   4423 int
   4424 bcm_esw_l2_learn_stat_set(int unit, bcm_l2_learn_stat_t *learn_stat)
   4425 {
   4426 #ifdef BCM_HURRICANE3_SUPPORT
   4427     if (soc_feature(unit, soc_feature_l2_learn_stats)) {
   4428         return _bcm_esw_l2_learn_stat_set(unit, learn_stat);
   4429     }
   4430 #endif /* BCM_HURRICANE3_SUPPORT */
   4431 
   4432     return (BCM_E_UNAVAIL);
   4433 }
   4434 
   4435 /*
   4436  * Function:
   4437  *     bcm_esw_l2_learn_stat_get
   4438  * Description:
   4439  *     To get the statistic of the specified L2 hash counter from chip.
   4440  * Parameters:
   4441  *      unit - (IN) Unit number.
   4442  *      learn_stat - (INOUT) Pointer to the L2 learned statistic structure.
   4443  * Return:
   4444  *     BCM_E_XXX
   4445  * Note:
   4446  *     The purposes of these counters are used to monitor the L2 hash condition.
   4447  *     When the counter counts to 32'hffff_ffff (maximum value), it will keep this value till
   4448  *     software clear it. Currently these L2 hash counters are system-wise.
   4449  */
   4450 int
   4451 bcm_esw_l2_learn_stat_get(int unit, bcm_l2_learn_stat_t *learn_stat)
   4452 {
   4453 #ifdef BCM_HURRICANE3_SUPPORT
   4454     if (soc_feature(unit, soc_feature_l2_learn_stats)) {
   4455         return _bcm_esw_l2_learn_stat_get(unit, learn_stat);
   4456     }
   4457 #endif /* BCM_HURRICANE3_SUPPORT */
   4458 
   4459     return (BCM_E_UNAVAIL);
   4460 }
   4461 
   4462 /*
   4463  * Function:
   4464  *     _bcm_esw_l2_entry_valid
   4465  * Description:
   4466  *      Check if given L2 entry is Valid
   4467  * Parameters:
   4468  *      unit         device number
   4469  *      mem         L2 memory to operate on
   4470  *      l2_entry    L2X entry read from HW
   4471  * Return:
   4472  *     BCM_E_NONE
   4473  *     BCM_E_NOT_FOUND
   4474  */
   4475 STATIC int 
   4476 _bcm_esw_l2_entry_valid(int unit, soc_memacc_t *l2x_memacc, uint32 *l2_entry)
   4477 {
   4478 #if defined(BCM_FIREBOLT_SUPPORT)
   4479     if (SOC_IS_FBX(unit)){
   4480         int valid;
   4481         if (soc_feature(unit, soc_feature_base_valid)) {
   4482             valid = soc_mem_field32_get(unit, L2Xm, l2_entry, BASE_VALIDf);
   4483         } else {
   4484             valid = soc_memacc_field32_get(&l2x_memacc[_BCM_L2_MEMACC_VALID],
   4485                                            l2_entry);
   4486         }
   4487         if (!valid) {
   4488             return BCM_E_NOT_FOUND;
   4489         }
   4490     }
   4491 #endif
   4492 #if defined(BCM_TRIUMPH_SUPPORT)
   4493     if (SOC_IS_TR_VL(unit)) {
   4494         int key_type;
   4495         key_type = soc_memacc_field32_get(&l2x_memacc[_BCM_L2_MEMACC_KEY_TYPE],
   4496                                           l2_entry);
   4497 #if defined(BCM_TRIDENT2_SUPPORT)
   4498         if (SOC_IS_TD2_TT2(unit)) {
   4499             if (key_type != TD2_L2_HASH_KEY_TYPE_BRIDGE &&
   4500                 key_type != TD2_L2_HASH_KEY_TYPE_VFI) {
   4501                 return BCM_E_NOT_FOUND;
   4502             }
   4503         } else
   4504 #endif
   4505 #if defined(BCM_GREYHOUND2_SUPPORT)
   4506         if (soc_feature(unit, soc_feature_vxlan_lite_riot)) {
   4507             if ((key_type != GH2_L2_HASH_KEY_TYPE_BRIDGE) &&
   4508                 (key_type != GH2_L2_HASH_KEY_TYPE_VFI) &&
   4509                 (key_type != GH2_L2_HASH_KEY_TYPE_VFI_MULTICAST)) {
   4510                 return BCM_E_NOT_FOUND;
   4511             }
   4512         } else
   4513 #endif /* BCM_GREYHOUND2_SUPPORT */
   4514 
   4515             /* Suppress coverity warning, because enum values used here
   4516              * for key_type are defined differently based on device type
   4517              */
   4518 
   4519             /* coverity[mixed_enums] */
   4520             if (key_type != TR_L2_HASH_KEY_TYPE_BRIDGE &&
   4521             key_type != TR_L2_HASH_KEY_TYPE_VFI) {
   4522             return BCM_E_NOT_FOUND;
   4523         }
   4524     }
   4525 #endif
   4526 
   4527     return BCM_E_NONE;
   4528 }
   4529 
   4530 /*
   4531  * Function:
   4532  *     _bcm_esw_l2_from_l2x
   4533  * Description:
   4534  *      Parser function to parse L2X entry into L2_Addr structure
   4535  *      will call per chip parser
   4536  * Parameters:
   4537  *      unit         device number
   4538  *      mem         L2 memory to operate on
   4539  *      l2addr      L2 address structure to fill
   4540  *      l2_entry    L2X entry read from HW
   4541  * Return:
   4542  *     BCM_E_XXX
   4543  */
   4544 int
   4545 _bcm_esw_l2_from_l2x(int unit, soc_mem_t mem, bcm_l2_addr_t *l2addr, uint32 *l2_entry)
   4546 {
   4547 #if defined(BCM_TRX_SUPPORT)
   4548     if (SOC_IS_TRX(unit)) {
   4549         if (EXT_L2_ENTRYm == mem) { 
   4550             return _bcm_tr_l2_from_ext_l2(unit, l2addr, 
   4551                                         (ext_l2_entry_entry_t *)l2_entry);
   4552         } else { 
   4553             return _bcm_tr_l2_from_l2x(unit, l2addr, 
   4554                                        (l2x_entry_t *)l2_entry);
   4555         }
   4556     } else
   4557 #endif 
   4558 #if defined(BCM_FIREBOLT_SUPPORT) || defined(BCM_BRADLEY_SUPPORT)
   4559     if (SOC_IS_FBX(unit)) {
   4560         return _bcm_fb_l2_from_l2x(unit, l2addr, 
   4561                                    (l2x_entry_t *)l2_entry);
   4562     } else
   4563 #endif
   4564 
   4565     return BCM_E_UNAVAIL;
   4566 }
   4567 
   4568 /*
   4569  * Function:
   4570  *     _bcm_esw_l2_traverse_mem
   4571  * Description:
   4572  *      Helper function to _bcm_esw_l2_traverse to itterate over given memory 
   4573  *      and actually read the table and parse entries.
   4574  * Parameters:
   4575  *     unit         device number
   4576  *      mem         L2 memory to read
   4577  *     trav_st      Traverse structure with all the data.
   4578  * Return:
   4579  *     BCM_E_XXX
   4580  */
   4581 int 
   4582 _bcm_esw_l2_traverse_mem(int unit, soc_mem_t mem, _bcm_l2_traverse_t *trav_st)
   4583 {
   4584     /* Indexes to iterate over memories, chunks and entries */
   4585     int             chnk_idx, ent_idx, chnk_idx_max, mem_idx_max;
   4586     int             buf_size, chunksize, chnk_end;
   4587     /* Buffer to store chunk of L2 table we currently work on */
   4588     uint32          *l2_tbl_chnk;
   4589     uint32          *l2_entry;
   4590     int             rv = BCM_E_NONE;
   4591     int             i;
   4592     soc_memacc_t    l2x_memacc_list[_BCM_L2_MEMACC_NUM];
   4593     soc_field_t     l2x_fields[_BCM_L2_MEMACC_NUM] = {
   4594         VALIDf,
   4595         KEY_TYPEf
   4596     };
   4597     _bcm_l2_replace_t *rep_st;
   4598     
   4599     if (!soc_mem_index_count(unit, mem)) {
   4600         return BCM_E_NONE;
   4601     }
   4602 
   4603     for (i = 0; i < _BCM_L2_MEMACC_NUM; i++) {
   4604         rv = soc_memacc_init(unit, mem, l2x_fields[i], &l2x_memacc_list[i]);
   4605         if (BCM_FAILURE(rv)) {
   4606             SOC_MEMACC_INVALID_SET(&l2x_memacc_list[i]);
   4607         }
   4608     }
   4609 
   4610     chunksize = soc_property_get(unit, spn_L2DELETE_CHUNKS,
   4611                                  L2_MEM_CHUNKS_DEFAULT);
   4612 
   4613     buf_size = 4 * SOC_MAX_MEM_FIELD_WORDS * chunksize;
   4614     l2_tbl_chnk = soc_cm_salloc(unit, buf_size, "l2 traverse");
   4615     if (NULL == l2_tbl_chnk) {
   4616         return BCM_E_MEMORY;
   4617     }
   4618 
   4619     mem_idx_max = soc_mem_index_max(unit, mem);
   4620     for (chnk_idx = soc_mem_index_min(unit, mem); 
   4621          chnk_idx <= mem_idx_max; 
   4622          chnk_idx += chunksize) {
   4623         sal_memset((void *)l2_tbl_chnk, 0, buf_size);
   4624 
   4625         chnk_idx_max = 
   4626             ((chnk_idx + chunksize) < mem_idx_max) ? 
   4627             (chnk_idx + chunksize - 1) : mem_idx_max;
   4628 
   4629         rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY,
   4630                                 chnk_idx, chnk_idx_max, l2_tbl_chnk);
   4631         if (SOC_FAILURE(rv)) {
   4632             break;
   4633         }
   4634 #if defined(BCM_TRIDENT2_SUPPORT)
   4635         if (SOC_IS_TRIDENT2(unit) || SOC_IS_TITAN2(unit)
   4636             || SOC_IS_TD2P_TT2P(unit)) {
   4637             rv = _bcm_td2_l2_hit_range_retrieve(unit, mem, chnk_idx, 
   4638                                                 chnk_idx_max, l2_tbl_chnk);
   4639             if (SOC_FAILURE(rv)) {
   4640                 break;
   4641             }
   4642         }
   4643 #endif /* BCM_TRIDENT2_SUPPORT */
   4644         chnk_end = (chnk_idx_max - chnk_idx);
   4645         for (ent_idx = 0 ; ent_idx <= chnk_end; ent_idx ++) {
   4646             l2_entry = 
   4647                 soc_mem_table_idx_to_pointer(unit, mem, uint32 *, 
   4648                                              l2_tbl_chnk, ent_idx);
   4649             if (BCM_FAILURE(_bcm_esw_l2_entry_valid(unit, l2x_memacc_list,
   4650                                                     l2_entry))) {
   4651                 continue;
   4652             }
   4653             trav_st->data = l2_entry;
   4654             trav_st->mem = mem;
   4655             trav_st->mem_idx = chnk_idx + ent_idx;
   4656             rv = trav_st->int_cb(unit, (void *)trav_st);
   4657             if (BCM_FAILURE(rv)) {
   4658                 break;
   4659             }
   4660         }
   4661         if (BCM_FAILURE(rv)) {
   4662             break;
   4663         }
   4664 
   4665         if (!trav_st->user_cb) {
   4666             /* Enhancement: use memory write range (per chunk) for replacing l2 entry data */
   4667             rep_st = ((_bcm_l2_traverse_t *)trav_st)->user_data;
   4668             if (mem == L2Xm && !(rep_st->flags & BCM_L2_REPLACE_DELETE)) {
   4669                 rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ANY,
   4670                                          chnk_idx, chnk_idx_max, l2_tbl_chnk);
   4671                 if (SOC_FAILURE(rv)) {
   4672                     break;
   4673                 }
   4674             }
   4675         }
   4676     }
   4677     soc_cm_sfree(unit, l2_tbl_chnk);
   4678     return rv;        
   4679 }
   4680 
   4681 /*
   4682  * Function:
   4683  *     _bcm_esw_l2_traverse
   4684  * Description:
   4685  *      Helper function to bcm_esw_l2_traverse to itterate over table 
   4686  *      and actually read the momery
   4687  * Parameters:
   4688  *     unit         device number
   4689  *     trav_st      Traverse structure with all the data.
   4690  * Return:
   4691  *     BCM_E_XXX
   4692  */
   4693 int 
   4694 _bcm_esw_l2_traverse(int unit, _bcm_l2_traverse_t *trav_st)
   4695 {
   4696     int rv = BCM_E_UNAVAIL; 
   4697 
   4698 #if defined(BCM_FIREBOLT_SUPPORT) || defined(BCM_BRADLEY_SUPPORT)
   4699     if (SOC_IS_FBX(unit)) {
   4700         rv = _bcm_esw_l2_traverse_mem(unit, L2Xm, trav_st);
   4701 #if defined(BCM_TRIUMPH_SUPPORT)
   4702         if (soc_feature(unit, soc_feature_esm_support) && BCM_SUCCESS(rv)) {
   4703             rv = _bcm_tr_l2_traverse_mem(unit, EXT_L2_ENTRYm, trav_st);
   4704         }
   4705 #endif  /* BCM_TRIUMPH_SUPPORT */
   4706 #if defined(BCM_HURRICANE3_SUPPORT)
   4707         if (soc_feature(unit, soc_feature_l2_overflow_bucket) && BCM_SUCCESS(rv)) {
   4708             rv = _bcm_esw_l2_traverse_mem(unit, L2_ENTRY_OVERFLOWm, trav_st);
   4709         }
   4710 #endif  /* BCM_HURRICANE3_SUPPORT */
   4711 
   4712     }
   4713 #endif  /* BCM_FBX_SUPPORT */
   4714     return rv;
   4715 }
   4716 
   4717 /*
   4718  * Function:
   4719  *     _bcm_esw_l2_traverse_int_cb
   4720  * Description:
   4721  *      Simple internal callback function for bcm_l2_traverse API just to call
   4722  *      a user provided callback on a given entry.
   4723  * Parameters:
   4724  *      unit         device number
   4725  *      trav_st      traverse structure
   4726  * Return:
   4727  *     BCM_E_XXX
   4728  */
   4729 int
   4730 _bcm_esw_l2_traverse_int_cb(int unit, void *trav_st)
   4731 {
   4732     _bcm_l2_traverse_t *trv;
   4733     bcm_l2_addr_t      l2_addr; 
   4734 
   4735     trv = (_bcm_l2_traverse_t *)trav_st;
   4736 
   4737     BCM_IF_ERROR_RETURN(
   4738         _bcm_esw_l2_from_l2x(unit, trv->mem, &l2_addr, trv->data));
   4739 
   4740     return trv->user_cb(unit, &l2_addr, trv->user_data);
   4741 }
   4742 
   4743 /*
   4744  * Function:
   4745  *     bcm_esw_l2_traverse
   4746  * Description:
   4747  *     To traverse the L2 table and call provided callback function with matched entry
   4748  * Parameters:
   4749  *     unit         device number
   4750  *     trav_fn      User specified callback function 
   4751  *     user_data    User specified cookie
   4752  * Return:
   4753  *     BCM_E_XXX
   4754  */
   4755 int 
   4756 bcm_esw_l2_traverse(int unit, bcm_l2_traverse_cb trav_fn, void *user_data)
   4757 {
   4758     _bcm_l2_traverse_t  trav_st;
   4759     
   4760 #if defined(BCM_TOMAHAWK3_SUPPORT)
   4761     /* Added to handle SDK functions calling esw version,
   4762      * instead of Tomahawk3's version
   4763      */
   4764     if (SOC_IS_TOMAHAWK3(unit)) {
   4765         return bcm_tomahawk3_l2_traverse(unit, trav_fn, user_data);
   4766     }
   4767 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   4768 
   4769     L2_INIT(unit);
   4770 
   4771     if (!trav_fn) {
   4772         return (BCM_E_PARAM);
   4773     }
   4774 
   4775     sal_memset(&trav_st, 0, sizeof(_bcm_l2_traverse_t));
   4776     
   4777     trav_st.user_cb = trav_fn;
   4778     trav_st.user_data = user_data;
   4779     trav_st.int_cb = _bcm_esw_l2_traverse_int_cb;
   4780 
   4781 #if defined(BCM_TRIUMPH3_SUPPORT)
   4782     if (soc_feature(unit, soc_feature_ism_memory)) {
   4783         return bcm_tr3_l2_traverse(unit, &trav_st);
   4784     }
   4785 #endif /* BCM_TRIUMPH3_SUPPORT */    
   4786 
   4787     return (_bcm_esw_l2_traverse(unit, &trav_st));
   4788 }
   4789 
   4790 int 
   4791 _bcm_esw_l2_match_sw(int unit, bcm_l2_addr_t *info, void *user_data)
   4792 {
   4793     int flag_match, vid_match, mac_match, dest_match;
   4794     _bcm_l2_match_t *l2match = user_data;
   4795 
   4796     flag_match = ((info->flags & l2match->addr_mask->flags) ==
   4797                   (l2match->match_addr->flags & l2match->addr_mask->flags));
   4798 
   4799     vid_match = ((info->vid & l2match->addr_mask->vid) ==
   4800                   (l2match->match_addr->vid & l2match->addr_mask->vid));
   4801 
   4802     {
   4803         uint8 *s = l2match->match_addr->mac, *d = info->mac;
   4804         uint8 *m = l2match->addr_mask->mac;
   4805 
   4806         mac_match = (((( s[0] & m[0] ) ^ (d[0] & m[0])) |
   4807                       (( s[1] & m[1] ) ^ (d[1] & m[1])) |
   4808                       (( s[2] & m[2] ) ^ (d[2] & m[2])) |
   4809                       (( s[3] & m[3] ) ^ (d[3] & m[3])) |
   4810                       (( s[4] & m[4] ) ^ (d[4] & m[4])) |
   4811                       (( s[5] & m[5] ) ^ (d[5] & m[5]))) == 0);
   4812     }
   4813 
   4814     {
   4815         if (BCM_MAC_IS_MCAST(info->mac)) {
   4816             dest_match = ((info->l2mc_group & l2match->addr_mask->l2mc_group) ==
   4817                           (l2match->match_addr->l2mc_group & l2match->addr_mask->l2mc_group));
   4818         } else if (info->flags & BCM_L2_TRUNK_MEMBER) {
   4819             dest_match = ((info->tgid & l2match->addr_mask->tgid) ==
   4820                           (l2match->match_addr->tgid & l2match->addr_mask->tgid));
   4821         } else if (BCM_GPORT_IS_SET(info->port)) {
   4822             dest_match = ((info->port & l2match->addr_mask->port) ==
   4823                           (l2match->match_addr->port & l2match->addr_mask->port));
   4824         } else {
   4825             dest_match = ((info->port & l2match->addr_mask->port) ==
   4826                           (l2match->match_addr->port & l2match->addr_mask->port));
   4827             dest_match &= ((info->modid & l2match->addr_mask->modid) ==
   4828                           (l2match->match_addr->modid & l2match->addr_mask->modid));
   4829         }
   4830     }
   4831 
   4832     if (flag_match && vid_match && mac_match && dest_match) {
   4833         l2match->trav_fn(unit, info, l2match->user_data);
   4834     }
   4835 
   4836     return 0;
   4837 }
   4838 
   4839 int
   4840 _bcm_esw_l2_matched_traverse(int unit, uint32 flags, bcm_l2_addr_t *match_addr,
   4841                              bcm_l2_traverse_cb trav_fn, void *user_data)
   4842 {
   4843     bcm_l2_addr_t addr_mask;
   4844     bcm_mac_t mac_mask = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
   4845     _bcm_l2_match_t l2match;
   4846 
   4847     if (!trav_fn) {
   4848         return (BCM_E_PARAM);
   4849     }
   4850 
   4851     if (!match_addr) {
   4852         return (BCM_E_PARAM);
   4853     }
   4854 
   4855     bcm_l2_addr_t_init(&addr_mask, mac_mask, 0xFFF);
   4856 
   4857     if (flags & BCM_L2_TRAVERSE_MATCH_STATIC) {
   4858         addr_mask.flags |= BCM_L2_STATIC;
   4859     } else {
   4860         addr_mask.flags &= ~BCM_L2_STATIC;
   4861     }
   4862 
   4863     if (flags & BCM_L2_TRAVERSE_MATCH_MAC) {
   4864         sal_memset(addr_mask.mac, 0xFF, sizeof(addr_mask.mac));
   4865     } else {
   4866         sal_memset(addr_mask.mac, 0x0, sizeof(addr_mask.mac));
   4867     }
   4868 
   4869     if (flags & BCM_L2_TRAVERSE_MATCH_VLAN) {
   4870         addr_mask.vid = ~0;
   4871     } else {
   4872         addr_mask.vid = 0;
   4873     }
   4874 
   4875     if (flags & BCM_L2_TRAVERSE_MATCH_DEST) {
   4876         addr_mask.port = ~0;
   4877         addr_mask.modid = ~0;
   4878         addr_mask.l2mc_group = ~0;
   4879         addr_mask.tgid = ~0;
   4880     } else {
   4881         addr_mask.port = 0x0;
   4882         addr_mask.modid = 0x0;
   4883         addr_mask.l2mc_group = 0x0;
   4884         addr_mask.tgid = 0x0;
   4885     }
   4886 
   4887     if (flags & BCM_L2_TRAVERSE_IGNORE_DISCARD_SRC) {
   4888         addr_mask.flags &= ~BCM_L2_DISCARD_SRC;
   4889     } else {
   4890         addr_mask.flags |= BCM_L2_DISCARD_SRC;
   4891     }
   4892 
   4893     if (flags & BCM_L2_TRAVERSE_IGNORE_DES_HIT) {
   4894         addr_mask.flags &= ~BCM_L2_DES_HIT;
   4895     } else {
   4896         addr_mask.flags |= BCM_L2_DES_HIT;
   4897     }
   4898 
   4899     l2match.match_addr = match_addr;
   4900     l2match.addr_mask = &addr_mask;
   4901     l2match.trav_fn =trav_fn;
   4902     l2match.user_data = user_data;
   4903 
   4904     return bcm_esw_l2_traverse(unit, _bcm_esw_l2_match_sw, &l2match);
   4905 }
   4906 
   4907 #ifdef BCM_XGS_SWITCH_SUPPORT
   4908 /*
   4909  * Function:
   4910  *     _bcm_get_op_from_flags
   4911  * Description:
   4912  *     Helper function to _bcm_fb_age_reg_config to 
   4913  *     decide on a PPA command according to flags
   4914  * Parameters:
   4915  *     flags        flags BCM_L2_REPLACE_* 
   4916  *     op           PPA command to be programmed
   4917  *     sync_op      Search Key for _soc_l2x_sync_delete_by
   4918  * Return:
   4919  *     BCM_E_NONE   - Success
   4920  *     BCM_E_PARAM  - Failure
   4921  */
   4922 int 
   4923 _bcm_get_op_from_flags(uint32 flags, uint32 *op, uint32 *sync_op)
   4924 {
   4925     uint32 cmp_flags = 0, int_op = 0, int_sync_op = 0;
   4926     int    rv = BCM_E_NONE;
   4927 
   4928     if (NULL == op) {
   4929         return BCM_E_PARAM;
   4930     }
   4931     cmp_flags = flags & (BCM_L2_REPLACE_MATCH_VLAN |
   4932                          BCM_L2_REPLACE_MATCH_DEST);
   4933     switch (cmp_flags) {
   4934         case BCM_L2_REPLACE_MATCH_VLAN: 
   4935         {
   4936             int_op = (flags & BCM_L2_REPLACE_DELETE ? XGS_PPAMODE_VLAN : 
   4937                    XGS_PPAMODE_VLAN_REPLACE);
   4938             int_sync_op = (flags & BCM_L2_REPLACE_DELETE ? SOC_L2X_VLAN_DEL : 
   4939                            SOC_L2X_NO_DEL);
   4940          break;
   4941         }
   4942         case BCM_L2_REPLACE_MATCH_DEST :
   4943         {
   4944             int_op = (flags & BCM_L2_REPLACE_DELETE ? XGS_PPAMODE_PORTMOD :
   4945                    XGS_PPAMODE_PORTMOD_REPLACE);
   4946             int_sync_op = (flags & BCM_L2_REPLACE_DELETE ? SOC_L2X_PORTMOD_DEL : 
   4947                            SOC_L2X_NO_DEL);
   4948             break;
   4949         }
   4950         case BCM_L2_REPLACE_MATCH_VLAN | BCM_L2_REPLACE_MATCH_DEST:
   4951         {
   4952             int_op = (flags & BCM_L2_REPLACE_DELETE ? XGS_PPAMODE_PORTMOD_VLAN :
   4953                    XGS_PPAMODE_PORTMOD_VLAN_REPLACE);
   4954             int_sync_op = (flags & BCM_L2_REPLACE_DELETE ? SOC_L2X_PORTMOD_VLAN_DEL : 
   4955                            SOC_L2X_NO_DEL);
   4956 
   4957             break;
   4958         }
   4959         default:
   4960             rv = BCM_E_PARAM;
   4961             break;
   4962     }
   4963 
   4964     *op = int_op;
   4965     *sync_op = int_sync_op;
   4966     return rv;
   4967 }
   4968 
   4969 #endif /* BCM_XGS_SWITCH_SUPPORT */
   4970 
   4971 
   4972 /*
   4973  * Function:
   4974  *     _bcm_l2_replace_limit_count_update
   4975  * Description:
   4976  *     Helper function to bcm_l2_replace API to update mac learn limit counters
   4977  * Parameters:
   4978  *      unit            device number
   4979  *      mem             memory for wich to update counters
   4980  *      rep_st          structure with information of replaced and new params
   4981  *      entry           The entry that is being updated.
   4982  * Return:
   4983  *     BCM_E_NONE   -   OK 
   4984  *     BCM_E_XXX    -   Error
   4985  */
   4986 STATIC int 
   4987 _bcm_l2_replace_limit_count_update(int unit, soc_mem_t mem, 
   4988                                    _bcm_l2_replace_t *rep_st, 
   4989                                    uint32 *entry)
   4990 {
   4991     int     index; 
   4992     uint32  rval, cnt_val, port_val, mac_cnt_entry;
   4993     soc_mem_t trunk_mem = TRUNK_GROUPm;
   4994 
   4995     if (soc_feature(unit, soc_feature_fastlag)) {
   4996         trunk_mem = FAST_TRUNK_GROUPm;
   4997     }
   4998 
   4999     /* If MAC learn limit not supported do nothing */
   5000     if ((!soc_feature(unit, soc_feature_mac_learn_limit))) {
   5001         return BCM_E_NONE;
   5002     }
   5003 
   5004     /* If MAC learn limit not enabled do nothing */
   5005     if (SOC_REG_IS_VALID(unit, MAC_LIMIT_ENABLEr)) {
   5006         BCM_IF_ERROR_RETURN(READ_MAC_LIMIT_ENABLEr(unit, &rval));
   5007         if (!soc_reg_field_get(unit, MAC_LIMIT_ENABLEr, rval, ENABLEf)) {
   5008             return BCM_E_NONE;
   5009         }
   5010     } else if (SOC_REG_IS_VALID(unit, SYS_MAC_LIMIT_CONTROLr)) {
   5011        BCM_IF_ERROR_RETURN(READ_SYS_MAC_LIMIT_CONTROLr(unit, &rval));
   5012        if (!soc_reg_field_get(unit, SYS_MAC_LIMIT_CONTROLr, rval, ENABLEf)) {
   5013            return BCM_E_NONE;
   5014        }
   5015     }
   5016     
   5017     /* If entry marked as EXEMPT do nothing */
   5018     if (soc_mem_field_valid(unit, mem, LIMIT_COUNTEDf)) {
   5019         if (!soc_mem_field32_get(unit,mem, entry, LIMIT_COUNTEDf)) {
   5020             return BCM_E_NONE;
   5021         }
   5022     }
   5023 
   5024     if (soc_mem_field_valid(unit, mem, TGID_PORTf)) { /* Draco Style */
   5025         port_val = soc_mem_field32_get(unit, mem, entry, TGID_PORTf);
   5026     } else { /* Triumph style */
   5027         port_val = soc_mem_field32_get(unit, mem, entry, PORT_NUMf);
   5028     }
   5029     if (soc_feature(unit, soc_feature_trunk_group_overlay)) {
   5030         if (soc_mem_field32_get(unit, mem, entry, Tf)) {
   5031             /* If trunk member - do nothing */
   5032             index = port_val;
   5033         } else {
   5034             index = port_val + soc_mem_index_count(unit, trunk_mem);
   5035         }
   5036     } else {
   5037         if (port_val & BCM_TGID_TRUNK_INDICATOR(unit)) {
   5038             /* If trunk member - do nothing */ 
   5039             index = port_val;
   5040         } else {
   5041             index = port_val + soc_mem_index_count(unit, trunk_mem);
   5042         }
   5043     }
   5044 
   5045     /* If match_dest contains trunk info it is there where we should do the decrement */
   5046     if ((rep_st->flags & BCM_L2_REPLACE_MATCH_DEST)) {
   5047         if (rep_st->match_dest.trunk != -1) {
   5048             index = rep_st->match_dest.trunk;
   5049         } else {
   5050             index = rep_st->match_dest.port +
   5051                 soc_mem_index_count(unit, trunk_mem);
   5052         }
   5053     }
   5054 
   5055     BCM_IF_ERROR_RETURN(
   5056         READ_PORT_OR_TRUNK_MAC_COUNTm(unit, MEM_BLOCK_ANY, index, 
   5057                                       &mac_cnt_entry));
   5058     cnt_val = soc_mem_field32_get(unit, PORT_OR_TRUNK_MAC_COUNTm, 
   5059                                   &mac_cnt_entry, COUNTf);
   5060     if ( 0 != cnt_val) {
   5061         cnt_val--;
   5062     }
   5063     soc_mem_field32_set(unit, PORT_OR_TRUNK_MAC_COUNTm, &mac_cnt_entry, 
   5064                         COUNTf, cnt_val);
   5065     BCM_IF_ERROR_RETURN(
   5066         WRITE_PORT_OR_TRUNK_MAC_COUNTm(unit, MEM_BLOCK_ALL, index,
   5067                                        &mac_cnt_entry));
   5068 
   5069     /* For replace cases a new index should be incremented. */
   5070     if (!(rep_st->flags & BCM_L2_REPLACE_DELETE)) {
   5071         if (rep_st->new_dest.trunk != -1) {
   5072             index = rep_st->new_dest.trunk;
   5073         } else {
   5074             index = rep_st->new_dest.port +
   5075                 soc_mem_index_count(unit, trunk_mem);
   5076         }
   5077         BCM_IF_ERROR_RETURN(
   5078         READ_PORT_OR_TRUNK_MAC_COUNTm(unit, MEM_BLOCK_ANY, index, 
   5079                                           &mac_cnt_entry));
   5080         cnt_val = soc_mem_field32_get(unit, PORT_OR_TRUNK_MAC_COUNTm, 
   5081                                       &mac_cnt_entry, COUNTf);
   5082         if ((++cnt_val) > 0x3FFF) {
   5083             cnt_val = 0x3FFF;
   5084         }
   5085         soc_mem_field32_set(unit, PORT_OR_TRUNK_MAC_COUNTm, &mac_cnt_entry, 
   5086                             COUNTf, cnt_val);
   5087         BCM_IF_ERROR_RETURN(
   5088         WRITE_PORT_OR_TRUNK_MAC_COUNTm(unit, MEM_BLOCK_ALL, index, 
   5089                                        &mac_cnt_entry));
   5090     }
   5091 
   5092     return BCM_E_NONE;
   5093 }
   5094 
   5095 
   5096 /*
   5097  * Function:
   5098  *     _bcm_l2_entry_replace
   5099  * Description:
   5100  *     Helper function to bcm_l2_replace API to be used as a call back for
   5101  *     bcm_l2_traverse API and replace given entry if MAC matches
   5102  * Parameters:
   5103  *     unit         device number
   5104  *     trav_st      structure with information from traverse function
   5105  * Return:
   5106  *     BCM_E_XXX
   5107  */
   5108 STATIC int
   5109 _bcm_l2_entry_replace(int unit, void *trav_st)
   5110 {
   5111     _bcm_l2_replace_t *rep_st;
   5112     soc_mem_t   mem;
   5113     uint32      *entry;
   5114     uint32      *match_data, *match_mask, *new_data, *new_mask;
   5115     int         entry_words, i, idx, rv;
   5116     bcm_mac_t   l2mac;
   5117     int         mod_val, port_val, trunk_val, vp_val;
   5118     soc_control_t   *soc = SOC_CONTROL(unit);
   5119     int         fifo_modified;
   5120     bcm_l2_addr_t l2_addr; 
   5121 
   5122     if (trav_st == NULL) {
   5123         return BCM_E_PARAM;
   5124     }
   5125 
   5126     mem = ((_bcm_l2_traverse_t *)trav_st)->mem;
   5127     entry = ((_bcm_l2_traverse_t *)trav_st)->data;
   5128     idx = ((_bcm_l2_traverse_t *)trav_st)->mem_idx;
   5129     rep_st = ((_bcm_l2_traverse_t *)trav_st)->user_data;
   5130 
   5131     if (rep_st == NULL || entry == NULL || mem == INVALIDm) {
   5132         return BCM_E_PARAM;
   5133     }
   5134 
   5135     if (mem == L2Xm) {
   5136         match_data = (uint32 *)&rep_st->match_data;
   5137         match_mask = (uint32 *)&rep_st->match_mask;
   5138         new_data = (uint32 *)&rep_st->new_data;
   5139         new_mask = (uint32 *)&rep_st->new_mask;
   5140         entry_words = soc_mem_entry_words(unit, mem);
   5141 #if defined(BCM_TRIDENT2_SUPPORT)
   5142          /* Retrieve the hit bit for TD2/TT2 */
   5143         if (rep_st->int_flags & _BCM_L2_REPLACE_INT_NO_ACTION) {
   5144             if (!SOC_IS_TOMAHAWKX(unit) && !SOC_IS_APACHE(unit) &&
   5145                 !SOC_IS_TRIDENT3X(unit) &&
   5146                     SOC_IS_TD2_TT2(unit)) {
   5147                 BCM_IF_ERROR_RETURN(
   5148                     _bcm_td2_l2_hit_retrieve(unit, (l2x_entry_t *)entry, idx));
   5149             }
   5150         }
   5151 #endif /* BCM_TRIDENT2_SUPPORT */                  
   5152         for (i = 0; i < entry_words; i++) {
   5153             if ((entry[i] ^ match_data[i]) & match_mask[i]) {
   5154                 return BCM_E_NONE;
   5155             }
   5156         }
   5157         if (rep_st->int_flags & _BCM_L2_REPLACE_INT_NO_ACTION) {
   5158             BCM_IF_ERROR_RETURN
   5159                 (_bcm_esw_l2_from_l2x(unit, mem, &l2_addr, entry));
   5160             return rep_st->trav_fn(unit, &l2_addr, rep_st->user_data);
   5161         }
   5162         if (rep_st->flags & BCM_L2_REPLACE_DELETE) {
   5163             if (SOC_CONTROL(unit)->l2x_mode == L2MODE_FIFO) {
   5164                 fifo_modified = FALSE;
   5165                 if ((rep_st->flags & BCM_L2_REPLACE_NO_CALLBACKS) &&
   5166                     soc_reg_field_valid(unit, AUX_ARB_CONTROLr,
   5167                                         L2_MOD_FIFO_ENABLE_L2_DELETEf) &&
   5168                     soc_l2mod_running(unit, NULL, NULL)) {
   5169                     BCM_IF_ERROR_RETURN
   5170                         (soc_reg_field32_modify(unit, AUX_ARB_CONTROLr,
   5171                                                 REG_PORT_ANY,
   5172                                                 L2_MOD_FIFO_ENABLE_L2_DELETEf,
   5173                                                 0));
   5174                     fifo_modified = TRUE;
   5175                 }
   5176                 rv = soc_mem_delete(unit, mem, MEM_BLOCK_ALL, entry);
   5177                 if (fifo_modified) {
   5178                     BCM_IF_ERROR_RETURN
   5179                         (soc_reg_field32_modify(unit, AUX_ARB_CONTROLr,
   5180                                                 REG_PORT_ANY,
   5181                                                 L2_MOD_FIFO_ENABLE_L2_DELETEf,
   5182                                                 1));
   5183                 }
   5184             } else {
   5185                 MEM_LOCK(unit, mem);
   5186                 if (SOC_L2_DEL_SYNC_LOCK(soc) < 0) {
   5187                     MEM_UNLOCK(unit, mem);
   5188                     return BCM_E_RESOURCE;
   5189                 }
   5190                 rv = soc_mem_delete(unit, mem, MEM_BLOCK_ALL, entry);
   5191 #ifdef BCM_XGS_SWITCH_SUPPORT
   5192                 if (BCM_SUCCESS(rv)) {
   5193                     rv = soc_l2x_sync_delete
   5194                         (unit, entry, idx,
   5195                          rep_st->flags & BCM_L2_REPLACE_NO_CALLBACKS ?
   5196                          SOC_L2X_NO_CALLBACKS : 0);
   5197                 }
   5198 #endif /* BCM_XGS_SWITCH_SUPPORT */
   5199                 SOC_L2_DEL_SYNC_UNLOCK(soc);
   5200                 MEM_UNLOCK(unit, mem);
   5201             }
   5202             return rv;
   5203         } else {
   5204             for (i = 0; i < entry_words; i++) {
   5205                 entry[i] &= ~new_mask[i];
   5206                 entry[i] |= new_data[i];
   5207             }
   5208             BCM_IF_ERROR_RETURN
   5209                 (_bcm_l2_replace_limit_count_update(unit, mem, rep_st, entry));
   5210 
   5211             /* Enhancement: use memory write range (per chunk) for replacing l2 entry data */
   5212             return BCM_E_NONE;
   5213         }
   5214     }
   5215 
   5216     if (rep_st->flags & BCM_L2_REPLACE_MATCH_VLAN) {
   5217         if (rep_st->key_vfi != -1) {
   5218 #ifdef BCM_TRIUMPH_SUPPORT
   5219             if (EXT_L2_ENTRYm == mem) {
   5220                 if (soc_mem_field32_get(unit, mem, entry, KEY_TYPE_VFIf) !=
   5221                     1) {
   5222                     return BCM_E_NONE;
   5223                 }
   5224             }
   5225 #endif /* BCM_TRIUMPH_SUPPORT */
   5226             if (soc_mem_field32_get(unit, mem, entry, VFIf) !=
   5227                 rep_st->key_vfi) {
   5228                 return BCM_E_NONE;
   5229             }
   5230         } else {
   5231 #ifdef BCM_TRIUMPH_SUPPORT
   5232             if (EXT_L2_ENTRYm == mem) {
   5233                 if (soc_mem_field32_get(unit, mem, entry, KEY_TYPE_VFIf) !=
   5234                     0) {
   5235                     return BCM_E_NONE;
   5236                 }
   5237             }
   5238 #endif /* BCM_TRIUMPH_SUPPORT */
   5239             if (soc_mem_field32_get(unit, mem, entry, VLAN_IDf) !=
   5240                 rep_st->key_vlan) {
   5241                 return BCM_E_NONE;
   5242             }
   5243         }
   5244     }
   5245 
   5246     if (rep_st->flags & BCM_L2_REPLACE_MATCH_MAC) {
   5247         soc_mem_mac_addr_get(unit, mem, entry, MAC_ADDRf, l2mac);
   5248         if (ENET_CMP_MACADDR(rep_st->key_mac, l2mac)) {
   5249             return BCM_E_NONE;
   5250         }
   5251     }
   5252 
   5253     if (rep_st->flags & BCM_L2_REPLACE_MATCH_DEST) {
   5254         vp_val = -1;
   5255         trunk_val = -1;
   5256         mod_val = -1;
   5257         port_val = -1;
   5258         if (soc_mem_field_valid(unit, mem, DEST_TYPEf) &&
   5259             soc_mem_field32_get(unit, mem, entry, DEST_TYPEf) == 2) {
   5260             vp_val = soc_mem_field32_get(unit, mem, entry, DESTINATIONf);
   5261         } else if (soc_feature(unit, soc_feature_trunk_group_overlay)) {
   5262             if (soc_mem_field32_get(unit, mem, entry, Tf)) {
   5263                 trunk_val = soc_mem_field32_get(unit, mem, entry, TGIDf);
   5264             } else {
   5265                 mod_val = soc_mem_field32_get(unit, mem, entry, MODULE_IDf);
   5266                 port_val = soc_mem_field32_get(unit, mem, entry, PORT_NUMf);
   5267             }
   5268         } else {
   5269             mod_val = soc_mem_field32_get(unit, mem, entry, MODULE_IDf);
   5270             port_val = soc_mem_field32_get(unit, mem, entry, TGID_PORTf);
   5271             if (port_val & BCM_TGID_TRUNK_INDICATOR(unit)) {
   5272                 trunk_val = BCM_MODIDf_TGIDf_TO_TRUNK(unit, mod_val, port_val);
   5273             }
   5274         }
   5275 
   5276         if (rep_st->match_dest.vp != -1) {
   5277             if (rep_st->match_dest.vp != vp_val) {
   5278                 return BCM_E_NONE;
   5279             }
   5280         } else if (rep_st->match_dest.trunk != -1) {
   5281             if (rep_st->match_dest.trunk != trunk_val) {
   5282                 return BCM_E_NONE;
   5283             }
   5284         } else {
   5285             if (rep_st->match_dest.module != mod_val) {
   5286                 return BCM_E_NONE;
   5287             }
   5288             if (rep_st->match_dest.port != port_val) {
   5289                 return BCM_E_NONE;
   5290             }
   5291         }
   5292     }
   5293 
   5294     if (!(rep_st->flags & BCM_L2_REPLACE_MATCH_STATIC)) {
   5295         /* BCM_L2_REPLACE_MATCH_STATIC means to replace static as well as
   5296          * non-static entries */
   5297         if (soc_mem_field32_get(unit, mem, entry, STATIC_BITf)) {
   5298             return BCM_E_NONE;
   5299         }
   5300     }
   5301 
   5302     /* BCM_L2_REPLACE_PENDING means to only replace pending entries,
   5303      * !BCM_L2_REPLACE_PENDING means to only replace non-pending entries. */
   5304     if (soc_mem_field_valid(unit, mem, PENDINGf)) {
   5305         if (soc_mem_field32_get(unit, mem, entry, PENDINGf)) {
   5306             if (!(rep_st->flags & BCM_L2_REPLACE_PENDING)) {
   5307                 return (BCM_E_NONE);
   5308             }
   5309         } else {
   5310             if (rep_st->flags & BCM_L2_REPLACE_PENDING) {
   5311                 return (BCM_E_NONE);
   5312             }
   5313         }
   5314     }
   5315 
   5316     if (rep_st->flags & BCM_L2_REPLACE_DELETE) {
   5317         if (mem != EXT_L2_ENTRYm) {
   5318             MEM_LOCK(unit, mem);
   5319             if (SOC_L2_DEL_SYNC_LOCK(soc) < 0) {
   5320                 MEM_UNLOCK(unit, mem);
   5321                 return BCM_E_RESOURCE;
   5322             }
   5323             rv = soc_mem_delete(unit, mem, MEM_BLOCK_ALL, entry);
   5324             if (BCM_FAILURE(rv)) {
   5325                 SOC_L2_DEL_SYNC_UNLOCK(soc);
   5326                 MEM_UNLOCK(unit, mem);
   5327                 return rv;
   5328             }
   5329 #ifdef BCM_XGS_SWITCH_SUPPORT
   5330             {
   5331                 uint32      soc_flags = 0; 
   5332                 soc_flags = (rep_st->flags & BCM_L2_REPLACE_NO_CALLBACKS) ? 
   5333                             SOC_L2X_NO_CALLBACKS : 0;
   5334                 rv = soc_l2x_sync_delete(unit, entry, idx, soc_flags);
   5335             }
   5336 #endif /* BCM_XGS_SWITCH_SUPPORT */
   5337             SOC_L2_DEL_SYNC_UNLOCK(soc);
   5338             MEM_UNLOCK(unit,  mem);
   5339             return rv;
   5340         }
   5341     } else {
   5342         if (rep_st->new_dest.vp != -1) { /* New destination is virtual port */
   5343             soc_mem_field32_set(unit, mem, entry, DEST_TYPEf, 0x2);
   5344             soc_mem_field32_set(unit, mem, entry, DESTINATIONf,
   5345                                 rep_st->new_dest.vp);
   5346         } else if (soc_feature(unit, soc_feature_trunk_group_overlay)) {
   5347             if (rep_st->new_dest.trunk != -1) { /* New destination is trunk */
   5348                 soc_mem_field32_set(unit, mem, entry, DEST_TYPEf, 1);
   5349                 soc_mem_field32_set(unit, mem, entry, TGIDf,
   5350                                     rep_st->new_dest.trunk);
   5351             } else { /* New destination is mod port */
   5352                 soc_mem_field32_set(unit, mem, entry, DEST_TYPEf, 0);
   5353                 soc_mem_field32_set(unit, mem, entry, MODULE_IDf,
   5354                                     rep_st->new_dest.module);
   5355                 soc_mem_field32_set(unit, mem, entry, PORT_NUMf,
   5356                                     rep_st->new_dest.port);
   5357             }
   5358         } else {
   5359             if (rep_st->new_dest.trunk != -1) { /* New destination is trunk */
   5360                 mod_val = BCM_TRUNK_TO_MODIDf(unit, rep_st->new_dest.trunk);
   5361                 port_val = BCM_TRUNK_TO_TGIDf(unit, rep_st->new_dest.trunk);
   5362                 soc_mem_field32_set(unit, mem, entry, MODULE_IDf, mod_val);
   5363                 soc_mem_field32_set(unit, mem, entry, TGID_PORTf, port_val);
   5364             } else { /* New destination is mod port */
   5365                 soc_mem_field32_set(unit, mem, entry, MODULE_IDf,
   5366                                     rep_st->new_dest.module);
   5367                 soc_mem_field32_set(unit, mem, entry, TGID_PORTf,
   5368                                     rep_st->new_dest.port);
   5369             }
   5370         }
   5371         BCM_IF_ERROR_RETURN(
   5372             _bcm_l2_replace_limit_count_update(unit, mem, rep_st, entry));
   5373     }
   5374 #ifdef BCM_TRIUMPH_SUPPORT
   5375     if (EXT_L2_ENTRYm == mem) {
   5376         if (rep_st->flags & BCM_L2_REPLACE_DELETE) {
   5377             BCM_IF_ERROR_RETURN(
   5378                 soc_mem_generic_delete(unit, mem, MEM_BLOCK_ANY, 0,
   5379                                        entry, entry, NULL));
   5380             /* learn limit counters should not be updated for static entries */
   5381             /* unless specifically instructed by API */
   5382             if ((rep_st->flags & BCM_L2_REPLACE_MATCH_STATIC)
   5383                 && !(rep_st->flags & BCM_L2_REPLACE_LEARN_LIMIT) ) {
   5384                 rv = BCM_E_NONE;
   5385             } else {
   5386                 rv = soc_triumph_learn_count_update(unit, (void *)entry,
   5387                                                     TRUE, -1);
   5388             }
   5389         } else {
   5390             rv = soc_mem_generic_insert(unit, mem, MEM_BLOCK_ALL, 0,
   5391                                         entry, entry, 0);
   5392             if (rv == BCM_E_EXISTS) {
   5393                 rv = BCM_E_NONE;
   5394             }
   5395         }
   5396         return rv;
   5397     }
   5398 #endif /* BCM_TRIUMPH_SUPPORT */
   5399 
   5400     return soc_mem_write(unit, mem, MEM_BLOCK_ALL, idx, entry);
   5401 }
   5402 
   5403 /*
   5404  * Function:
   5405  *     _bcm_l2_replace_by_hw
   5406  * Description:
   5407  *     Helper function to bcm_l2_replace API to replace l2 entries by hardware
   5408  * Parameters:
   5409  *     unit         device number
   5410  *     flags        flags BCM_L2_REPLACE_* 
   5411  *     rep_st       structure with information of what to replace 
   5412  * Return:
   5413  *     BCM_E_XXX
   5414  */
   5415 STATIC int 
   5416 _bcm_l2_replace_by_hw(int unit, uint32 flags, _bcm_l2_replace_t *rep_st)
   5417 {
   5418 #ifdef BCM_TRX_SUPPORT
   5419     if (SOC_IS_TRX(unit)) {
   5420         return _bcm_tr_l2_replace_by_hw(unit, rep_st);
   5421     }
   5422 #endif /* BCM_TRX_SUPPORT */
   5423 #ifdef BCM_FIREBOLT_SUPPORT
   5424     if (SOC_IS_FBX(unit)) {
   5425         return _bcm_fb_l2_addr_replace_by_vlan_dest(unit, flags, rep_st);
   5426     }
   5427 #endif /* BCM_FIREBOLT_SUPPORT */
   5428     
   5429     return BCM_E_UNAVAIL;
   5430 }
   5431 
   5432 /*
   5433  * Function:
   5434  *     _bcm_l2_replace_dest_setup
   5435  * Description:
   5436  *     Helper function to bcm_l2_replace API to setup a destination
   5437  */
   5438 STATIC int
   5439 _bcm_l2_replace_dest_setup(int unit, bcm_module_t module, bcm_port_t port,
   5440                            bcm_trunk_t trunk, int is_trunk,
   5441                            _bcm_l2_replace_dest_t *dest)
   5442 {
   5443     int tid_is_vp_lag;
   5444     int vp;
   5445 #if defined(BCM_TRIDENT2_SUPPORT) && defined(INCLUDE_L3)
   5446     int vp_lag_vp;
   5447 #endif /* BCM_TRIDENT2_SUPPORT && INCLUDE_L3 */
   5448 
   5449     /* If all are -1, means ignore the replacement with new destination */
   5450     if (module == -1 && port == -1 && trunk == -1) {
   5451         dest->module = dest->port = dest->trunk = dest->vp = -1;
   5452         return BCM_E_NONE;
   5453     }
   5454 
   5455     if (BCM_GPORT_IS_SET(port)) {
   5456         if (BCM_GPORT_IS_MPLS_PORT(port) ||
   5457             BCM_GPORT_IS_SUBPORT_GROUP(port) ||
   5458             BCM_GPORT_IS_SUBPORT_PORT(port) ||
   5459             BCM_GPORT_IS_MIM_PORT(port) ||
   5460             BCM_GPORT_IS_VLAN_PORT(port) ||
   5461             BCM_GPORT_IS_WLAN_PORT(port) ||
   5462             BCM_GPORT_IS_TRILL_PORT(port) ||
   5463             BCM_GPORT_IS_NIV_PORT(port) ||
   5464             BCM_GPORT_IS_VXLAN_PORT(port) ||
   5465             BCM_GPORT_IS_L2GRE_PORT(port) ||
   5466             BCM_GPORT_IS_EXTENDER_PORT(port)) {
   5467 
   5468 #ifdef BCM_KATANA2_SUPPORT
   5469             if (BCM_GPORT_IS_SUBPORT_PORT(port) &&
   5470                 _BCM_KT2_GPORT_IS_LINKPHY_OR_SUBTAG_SUBPORT_GPORT(unit, port)) {
   5471             } else
   5472 #endif
   5473             {
   5474                 /* all these gport has similar encoding format */
   5475                 vp = port & 0xffffff;
   5476 
   5477                 if (!SOC_MEM_IS_VALID(unit, SOURCE_VPm) ||
   5478                     vp > soc_mem_index_max(unit, SOURCE_VPm)) {
   5479                     return BCM_E_PORT;
   5480                 }
   5481                 dest->vp = vp;
   5482             }
   5483         } else {
   5484             BCM_IF_ERROR_RETURN
   5485                 (_bcm_esw_gport_resolve(unit, port, &dest->module, &dest->port,
   5486                                         &dest->trunk, &dest->vp));
   5487         }
   5488 
   5489 #if defined(BCM_HGPROXY_COE_SUPPORT)
   5490         if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
   5491             _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port)) {
   5492             BCM_IF_ERROR_RETURN
   5493                 (_bcm_esw_gport_resolve(unit, port, &dest->module, &dest->port,
   5494                                         &dest->trunk, &dest->vp));
   5495             dest->vp = -1;
   5496         }
   5497 #endif
   5498 
   5499 #if defined(BCM_KATANA2_SUPPORT)
   5500         if (_BCM_KT2_GPORT_IS_LINKPHY_OR_SUBTAG_SUBPORT_GPORT(unit, port)) {
   5501             BCM_IF_ERROR_RETURN
   5502                 (_bcm_esw_gport_resolve(unit, port, &dest->module, &dest->port,
   5503                                         &dest->trunk, &dest->vp));
   5504             dest->vp = -1;
   5505         }
   5506 #endif
   5507     } else if (is_trunk) {
   5508         BCM_IF_ERROR_RETURN(_bcm_trunk_id_validate(unit, trunk));
   5509         BCM_IF_ERROR_RETURN(
   5510             _bcm_esw_trunk_id_is_vp_lag(unit, trunk, &tid_is_vp_lag));
   5511         if (tid_is_vp_lag) {
   5512 #if defined(BCM_TRIDENT2_SUPPORT) && defined(INCLUDE_L3)
   5513             if (soc_feature(unit, soc_feature_vp_lag)) {
   5514                 /* Get the VP value representing VP LAG */
   5515                 BCM_IF_ERROR_RETURN(
   5516                     _bcm_esw_trunk_tid_to_vp_lag_vp(unit, trunk, &vp_lag_vp));
   5517                 dest->vp = vp_lag_vp;
   5518                 dest->trunk = -1;
   5519             } else
   5520 #endif /* BCM_TRIDENT2_SUPPORT && INCLUDE_L3 */
   5521             {
   5522                 return BCM_E_PORT;
   5523             }
   5524         } else {
   5525             dest->trunk = trunk;
   5526             dest->vp = -1;
   5527         }
   5528     } else {
   5529         BCM_IF_ERROR_RETURN
   5530             (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET, module, port,
   5531                                      &dest->module, &dest->port));
   5532         if (!SOC_MODID_ADDRESSABLE(unit, dest->module)) {
   5533             return BCM_E_BADID;
   5534         }
   5535         if (!SOC_PORT_ADDRESSABLE(unit, dest->port)) {
   5536             return BCM_E_PORT;
   5537         }
   5538         dest->trunk = -1;
   5539         dest->vp = -1;
   5540     }
   5541 
   5542     return BCM_E_NONE;
   5543 }
   5544 
   5545 STATIC int
   5546 _bcm_l2_replace_data_mask_setup(int unit, _bcm_l2_replace_t *rep)
   5547 {
   5548     bcm_mac_t mac_mask;
   5549     bcm_mac_t mac_data;
   5550     int field_len;
   5551     uint32 module, port;
   5552 
   5553     sal_memset(&rep->match_mask, 0, sizeof(l2x_entry_t));
   5554     sal_memset(&rep->match_data, 0, sizeof(l2x_entry_t));
   5555     sal_memset(&rep->new_mask, 0, sizeof(l2x_entry_t));
   5556     sal_memset(&rep->new_data, 0, sizeof(l2x_entry_t));
   5557 
   5558     if (soc_feature(unit, soc_feature_base_valid)) {
   5559         soc_mem_field32_set(unit, L2Xm, &rep->match_mask, BASE_VALIDf, 1);
   5560         soc_mem_field32_set(unit, L2Xm, &rep->match_data, BASE_VALIDf, 1);
   5561     } else if (soc_mem_field_valid(unit, L2Xm, VALIDf)) {
   5562         soc_mem_field32_set(unit, L2Xm, &rep->match_mask, VALIDf, 1);
   5563         soc_mem_field32_set(unit, L2Xm, &rep->match_data, VALIDf, 1);
   5564     }
   5565 
   5566     if (SOC_IS_TR_VL(unit) && (rep->key_type != -1)) {
   5567         field_len = soc_mem_field_length(unit, L2Xm, KEY_TYPEf);
   5568         soc_mem_field32_set(unit, L2Xm, &rep->match_mask, KEY_TYPEf,
   5569                             (1 << field_len) - 1);
   5570         soc_mem_field32_set(unit, L2Xm, &rep->match_data, KEY_TYPEf,
   5571                             rep->key_type);
   5572     }
   5573 
   5574     if (rep->flags & BCM_L2_REPLACE_MATCH_VLAN) {
   5575         if (rep->key_vfi != -1) {
   5576             field_len = soc_mem_field_length(unit, L2Xm, VFIf);
   5577             soc_mem_field32_set(unit, L2Xm, &rep->match_mask, VFIf,
   5578                                 (1 << field_len) - 1);
   5579             soc_mem_field32_set(unit, L2Xm, &rep->match_data, VFIf,
   5580                                 rep->key_vfi);
   5581         } else {
   5582             soc_mem_field32_set(unit, L2Xm, &rep->match_mask, VLAN_IDf, 0xfff);
   5583             soc_mem_field32_set(unit, L2Xm, &rep->match_data, VLAN_IDf,
   5584                                 rep->key_vlan);
   5585         }
   5586     }
   5587 
   5588     if (rep->flags & BCM_L2_REPLACE_MATCH_MAC) {
   5589         sal_memset(&mac_mask, 0xff, sizeof(mac_mask));
   5590         soc_mem_mac_addr_set(unit, L2Xm, &rep->match_mask, MAC_ADDRf,
   5591                              mac_mask);
   5592         soc_mem_mac_addr_set(unit, L2Xm, &rep->match_data, MAC_ADDRf,
   5593                              rep->key_mac);
   5594     }
   5595 
   5596     if ((rep->flags & BCM_L2_REPLACE_MATCH_UC) && 
   5597         !(rep->flags & BCM_L2_REPLACE_MATCH_MC)) {
   5598         /* The 40th bit of Unicast must be 0 */
   5599         sal_memset(&mac_mask, 0x00, sizeof(mac_mask));
   5600         mac_mask[0] = 0x01;
   5601         sal_memset(&mac_data, 0x00, sizeof(mac_data));
   5602         soc_mem_mac_addr_set(unit, L2Xm, &rep->match_mask, MAC_ADDRf,
   5603                              mac_mask);
   5604         soc_mem_mac_addr_set(unit, L2Xm, &rep->match_data, MAC_ADDRf,
   5605                              mac_data);
   5606     } else if ((rep->flags & BCM_L2_REPLACE_MATCH_MC) &&
   5607         !(rep->flags & BCM_L2_REPLACE_MATCH_UC)) {
   5608         /* The 40th bit of Multicast must be 1 */
   5609         sal_memset(&mac_mask, 0x00, sizeof(mac_mask));
   5610         mac_mask[0] = 0x01;
   5611         sal_memset(&mac_data, 0x00, sizeof(mac_data));
   5612         mac_data[0] = 0x01;
   5613         soc_mem_mac_addr_set(unit, L2Xm, &rep->match_mask, MAC_ADDRf,
   5614                              mac_mask);
   5615         soc_mem_mac_addr_set(unit, L2Xm, &rep->match_data, MAC_ADDRf,
   5616                              mac_data);
   5617     }
   5618 
   5619     if (rep->flags & BCM_L2_REPLACE_MATCH_DEST) {
   5620         if (rep->match_dest.vp != -1) {
   5621             if (soc_feature(unit, soc_feature_generic_dest)) {
   5622                 field_len = soc_mem_field_length(unit, L2Xm, DESTINATIONf);
   5623                 soc_mem_field32_set(unit, L2Xm, &rep->match_mask, DESTINATIONf, 
   5624                                     (1 << field_len) - 1);
   5625                 soc_mem_field32_dest_set(unit, L2Xm, &rep->match_data, 
   5626                     DESTINATIONf, SOC_MEM_FIF_DEST_DVP, rep->match_dest.vp);
   5627             } else {
   5628                 field_len = soc_mem_field_length(unit, L2Xm, DEST_TYPEf);
   5629                 soc_mem_field32_set(unit, L2Xm, &rep->match_mask, DEST_TYPEf,
   5630                                     (1 << field_len) - 1);
   5631                 soc_mem_field32_set(unit, L2Xm, &rep->match_data, DEST_TYPEf, 2);
   5632 
   5633                 field_len = soc_mem_field_length(unit, L2Xm, DESTINATIONf);
   5634                 soc_mem_field32_set(unit, L2Xm, &rep->match_mask, DESTINATIONf,
   5635                                     (1 << field_len) - 1);
   5636                 soc_mem_field32_set(unit, L2Xm, &rep->match_data, DESTINATIONf,
   5637                                     rep->match_dest.vp);
   5638             }
   5639         } else {
   5640             if (soc_feature(unit, soc_feature_trunk_group_overlay)) {
   5641                 if (soc_feature(unit, soc_feature_generic_dest)) {
   5642                     field_len = soc_mem_field_length(unit, L2Xm, DESTINATIONf);
   5643                     if (rep->match_dest.trunk != -1) {
   5644                         soc_mem_field32_set(unit, L2Xm, &rep->match_mask, DESTINATIONf,
   5645                                             (1 << field_len) - 1);
   5646                         soc_mem_field32_dest_set(unit, L2Xm, &rep->match_data,
   5647                             DESTINATIONf, SOC_MEM_FIF_DEST_LAG, rep->match_dest.trunk);
   5648                     } else {
   5649                         if (rep->match_dest.port != -1) {
   5650                             soc_mem_field32_set(unit, L2Xm, &rep->match_mask, DESTINATIONf,
   5651                                                 (1 << field_len) - 1);
   5652                             soc_mem_field32_dest_set(unit, L2Xm, &rep->match_data,
   5653                                 DESTINATIONf, SOC_MEM_FIF_DEST_DGPP,
   5654                                 rep->match_dest.module << SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS |
   5655                                 rep->match_dest.port);
   5656                         } else {
   5657                             soc_mem_field32_dest_set(unit, L2Xm, &rep->match_mask,
   5658                                 DESTINATIONf, SOC_MEM_FIF_DEST_DGPP,
   5659                                 0xff << SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS | 0);
   5660                             soc_mem_field32_dest_set(unit, L2Xm, &rep->match_data,
   5661                                 DESTINATIONf, SOC_MEM_FIF_DEST_DGPP,
   5662                                 rep->match_dest.module << SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS |
   5663                                 0);
   5664                         }
   5665 
   5666                         if (!(rep->flags & BCM_L2_REPLACE_MATCH_MAC)) {
   5667                             /* Ignore multicast mac from bulk delete */
   5668                             mac_mask[0] = 0x01;
   5669                             mac_mask[1] = mac_mask[2] = mac_mask[3] =
   5670                                           mac_mask[4] = mac_mask[5] = 0x00;
   5671                             soc_mem_mac_addr_set(unit, L2Xm, &rep->match_mask,
   5672                                 MAC_ADDRf, mac_mask);
   5673                         }
   5674                     }
   5675                 } else {
   5676                     field_len = soc_mem_field_length(unit, L2Xm, DEST_TYPEf);
   5677                     soc_mem_field32_set(unit, L2Xm, &rep->match_mask, DEST_TYPEf,
   5678                                         (1 << field_len) - 1);
   5679 
   5680                     if (rep->match_dest.trunk != -1) {
   5681                         soc_mem_field32_set(unit, L2Xm, &rep->match_data,
   5682                                             DEST_TYPEf, 1);
   5683 
   5684                         field_len = soc_mem_field_length(unit, L2Xm, TGIDf);
   5685                         soc_mem_field32_set(unit, L2Xm, &rep->match_mask, TGIDf,
   5686                                             (1 << field_len) - 1);
   5687                         soc_mem_field32_set(unit, L2Xm, &rep->match_data, TGIDf,
   5688                                             rep->match_dest.trunk);
   5689                     } else {
   5690                         /* DEST_TYPE field in data is 0 */
   5691 
   5692                         field_len = soc_mem_field_length(unit, L2Xm, MODULE_IDf);
   5693                         soc_mem_field32_set(unit, L2Xm, &rep->match_mask,
   5694                                             MODULE_IDf, (1 << field_len) - 1);
   5695                         soc_mem_field32_set(unit, L2Xm, &rep->match_data,
   5696                                             MODULE_IDf, rep->match_dest.module);
   5697                         if (rep->match_dest.port != -1) {
   5698                             field_len = soc_mem_field_length(unit, L2Xm, PORT_NUMf);
   5699                             soc_mem_field32_set(unit, L2Xm, &rep->match_mask,
   5700                                                 PORT_NUMf, (1 << field_len) - 1);
   5701                             soc_mem_field32_set(unit, L2Xm, &rep->match_data,
   5702                                                 PORT_NUMf, rep->match_dest.port);
   5703                         }
   5704 
   5705                         if (!(rep->flags & BCM_L2_REPLACE_MATCH_MAC)) {
   5706                             /* Ignore multicast mac from bulk delete */
   5707                             mac_mask[0] = 0x01;
   5708                             mac_mask[1] = mac_mask[2] = mac_mask[3] =
   5709                                           mac_mask[4] = mac_mask[5] = 0x00;
   5710                             soc_mem_mac_addr_set(unit, L2Xm, &rep->match_mask,
   5711                                 MAC_ADDRf, mac_mask);
   5712                         }
   5713                     }
   5714                 } /* soc_feature_generic_dest */
   5715             } else {
   5716                 if (rep->match_dest.trunk != -1) {
   5717                     module = BCM_TRUNK_TO_MODIDf(unit, rep->match_dest.trunk);
   5718                     port = BCM_TRUNK_TO_TGIDf(unit, rep->match_dest.trunk);
   5719                 } else {
   5720                     module = rep->match_dest.module;
   5721                     port = rep->match_dest.port;
   5722                 }
   5723 
   5724                 field_len = soc_mem_field_length(unit, L2Xm, MODULE_IDf);
   5725                 soc_mem_field32_set(unit, L2Xm, &rep->match_mask, MODULE_IDf,
   5726                                     (1 << field_len) - 1);
   5727                 soc_mem_field32_set(unit, L2Xm, &rep->match_data, MODULE_IDf,
   5728                                     module);
   5729                 if (port != -1) {
   5730                     field_len = soc_mem_field_length(unit, L2Xm, TGID_PORTf);
   5731                     soc_mem_field32_set(unit, L2Xm, &rep->match_mask, TGID_PORTf,
   5732                                         (1 << field_len) - 1);
   5733                     soc_mem_field32_set(unit, L2Xm, &rep->match_data, TGID_PORTf,
   5734                                         port);
   5735                 }
   5736             }
   5737         }
   5738     }
   5739     
   5740     /* BCM_L2_REPLACE_MATCH_STATIC means to replace static as well as
   5741     * non-static entries */
   5742     if (!(rep->flags & BCM_L2_REPLACE_MATCH_STATIC)) { 
   5743         if (rep->int_flags & _BCM_L2_REPLACE_INT_MATCH_ONLY_STATIC) { 
   5744             soc_mem_field32_set(unit, L2Xm, &rep->match_mask, STATIC_BITf, 1); 
   5745             soc_mem_field32_set(unit, L2Xm, &rep->match_data, STATIC_BITf, 1); 
   5746         } else { 
   5747             soc_mem_field32_set(unit, L2Xm, &rep->match_mask, STATIC_BITf, 1);
   5748             /* STATIC_BIT field in data is 0 */ 
   5749         } 
   5750     }
   5751     /* STATIC_BIT field in mask is 0 */ 
   5752 #ifdef BCM_TRIDENT2PLUS_SUPPORT
   5753     if (SOC_IS_TRIDENT2PLUS(unit) || SOC_IS_TRIDENT3X(unit)) {
   5754         if (rep->flags & BCM_L2_REPLACE_MATCH_CLASS_ID) {
   5755             soc_mem_field32_set(unit, L2Xm, &rep->match_mask, CLASS_IDf, 0x3f);
   5756             soc_mem_field32_set(unit, L2Xm, &rep->match_data, CLASS_IDf, rep->key_class_id);
   5757         }
   5758         if (rep->flags & BCM_L2_REPLACE_MATCH_INT_PRI) {
   5759             soc_mem_field32_set(unit, L2Xm, &rep->match_mask, RPEf, 0x1);
   5760             soc_mem_field32_set(unit, L2Xm, &rep->match_data, RPEf, 1);
   5761             soc_mem_field32_set(unit, L2Xm, &rep->match_mask, PRIf, 0x1);
   5762             soc_mem_field32_set(unit, L2Xm, &rep->match_data, PRIf, rep->key_int_pri);
   5763          }
   5764     }
   5765 #endif /*BCM_TRIDENT2PLUS_SUPPORT*/
   5766     if (soc_mem_field_valid(unit, L2Xm, PENDINGf)) {
   5767         soc_mem_field32_set(unit, L2Xm, &rep->match_mask, PENDINGf, 1);
   5768         if (rep->flags & BCM_L2_REPLACE_PENDING) {
   5769             soc_mem_field32_set(unit, L2Xm, &rep->match_data, PENDINGf, 1);
   5770         }
   5771     }
   5772 
   5773     if (rep->int_flags & _BCM_L2_REPLACE_INT_MATCH_DISCARD_SRC) {
   5774         soc_mem_field32_set(unit, L2Xm, &rep->match_mask, SRC_DISCARDf, 1);
   5775         if (rep->key_l2_flags & BCM_L2_DISCARD_SRC) {
   5776             soc_mem_field32_set(unit, L2Xm, &rep->match_data, SRC_DISCARDf, 1);
   5777         }
   5778     }
   5779 
   5780     if (rep->int_flags & _BCM_L2_REPLACE_INT_MATCH_SRC_HIT) {
   5781         soc_mem_field32_set(unit, L2Xm, &rep->match_mask, HITSAf, 1);
   5782         if (rep->key_l2_flags & BCM_L2_SRC_HIT) {
   5783             soc_mem_field32_set(unit, L2Xm, &rep->match_data, HITSAf, 1);
   5784         }
   5785     }
   5786     if (rep->int_flags & _BCM_L2_REPLACE_INT_MATCH_DES_HIT) {
   5787         soc_mem_field32_set(unit, L2Xm, &rep->match_mask, HITDAf, 1);
   5788         if (rep->key_l2_flags & BCM_L2_DES_HIT) {
   5789             soc_mem_field32_set(unit, L2Xm, &rep->match_data, HITDAf, 1);
   5790         }
   5791     }
   5792     if (SOC_MEM_FIELD_VALID(unit, L2Xm, LOCAL_SAf)) {
   5793         if (rep->int_flags & _BCM_L2_REPLACE_INT_MATCH_NATIVE) {
   5794             soc_mem_field32_set(unit, L2Xm, &rep->match_mask, LOCAL_SAf, 1);
   5795             if (rep->key_l2_flags & BCM_L2_NATIVE) {
   5796                 soc_mem_field32_set(unit, L2Xm, &rep->match_data, LOCAL_SAf,
   5797                                     1);
   5798             }
   5799         }
   5800     }
   5801     if (_CLEAR_ALL_ENTRIES_SRC_OR_DES_HIT_BIT(rep->flags)) {
   5802         if (rep->flags & BCM_L2_REPLACE_DES_HIT_CLEAR) {
   5803             soc_mem_field32_set(unit, L2Xm, &rep->match_mask, HITDAf, 1);
   5804             soc_mem_field32_set(unit, L2Xm, &rep->match_data, HITDAf, 1);
   5805         }
   5806         if (rep->flags & BCM_L2_REPLACE_SRC_HIT_CLEAR) {
   5807             soc_mem_field32_set(unit, L2Xm, &rep->match_mask, HITSAf, 1);
   5808             soc_mem_field32_set(unit, L2Xm, &rep->match_data, HITSAf, 1);
   5809         }
   5810     }
   5811     if (!(rep->flags & (BCM_L2_REPLACE_DELETE | BCM_L2_REPLACE_AGE))) {
   5812         if (!_CLEAR_ALL_ENTRIES_SRC_OR_DES_HIT_BIT(rep->flags)) {
   5813             if (rep->new_dest.vp != -1) {
   5814                 if (soc_feature(unit, soc_feature_generic_dest)) {
   5815                     field_len = soc_mem_field_length(unit, L2Xm, DESTINATIONf);
   5816                     soc_mem_field32_set(unit, L2Xm, &rep->new_mask, DESTINATIONf, 
   5817                                     (1 << field_len) - 1);
   5818                     soc_mem_field32_dest_set(unit, L2Xm, &rep->new_data, 
   5819                         DESTINATIONf, SOC_MEM_FIF_DEST_DVP, rep->new_dest.vp);
   5820                 } else {
   5821                     field_len = soc_mem_field_length(unit, L2Xm, DEST_TYPEf);
   5822                     soc_mem_field32_set(unit, L2Xm, &rep->new_mask, DEST_TYPEf,
   5823                                         (1 << field_len) - 1);
   5824                     soc_mem_field32_set(unit, L2Xm, &rep->new_data, DEST_TYPEf, 2);
   5825                     field_len = soc_mem_field_length(unit, L2Xm, DESTINATIONf);
   5826                     soc_mem_field32_set(unit, L2Xm, &rep->new_mask, DESTINATIONf,
   5827                                         (1 << field_len) - 1);
   5828                     soc_mem_field32_set(unit, L2Xm, &rep->new_data, DESTINATIONf,
   5829                                         rep->new_dest.vp);
   5830                 }
   5831             } else {
   5832                 if (soc_feature(unit, soc_feature_trunk_group_overlay)) {
   5833                     if (soc_feature(unit, soc_feature_generic_dest)) {
   5834                         field_len = soc_mem_field_length(unit, L2Xm, DESTINATIONf);
   5835                         soc_mem_field32_set(unit, L2Xm, &rep->new_mask, DESTINATIONf,
   5836                                             (1 << field_len) - 1);
   5837                         if (rep->new_dest.trunk != -1) {
   5838                             soc_mem_field32_dest_set(unit, L2Xm, &rep->new_data, 
   5839                                 DESTINATIONf, SOC_MEM_FIF_DEST_LAG, rep->new_dest.trunk);
   5840                         } else {
   5841                             soc_mem_field32_dest_set(unit, L2Xm, &rep->new_data, 
   5842                                 DESTINATIONf, SOC_MEM_FIF_DEST_DGPP, 
   5843                                 rep->new_dest.module << SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS | 
   5844                                 rep->new_dest.port);
   5845                         }
   5846                     } else {
   5847                         if (rep->new_dest.trunk != -1) {
   5848                             field_len = soc_mem_field_length(unit, L2Xm, DEST_TYPEf);
   5849                             soc_mem_field32_set(unit, L2Xm, &rep->new_mask, DEST_TYPEf,
   5850                                                 (1 << field_len) - 1);
   5851 
   5852                             soc_mem_field32_set(unit, L2Xm, &rep->new_data, DEST_TYPEf,
   5853                                                 1);
   5854 
   5855                             /*
   5856                              * Writing to DESTINATION field instead of TGIDf
   5857                              * to ensure the MSB bits of DESTINATION are cleared.
   5858                              */
   5859                             field_len = soc_mem_field_length(unit, L2Xm,
   5860                                     DESTINATIONf);
   5861                             soc_mem_field32_set(unit, L2Xm, &rep->new_mask,
   5862                                     DESTINATIONf, (1 << field_len) - 1);
   5863                             soc_mem_field32_set(unit, L2Xm, &rep->new_data,
   5864                                     DESTINATIONf, rep->new_dest.trunk);
   5865                         } else if (rep->new_dest.port != -1 
   5866                                    && rep->new_dest.module != -1) {
   5867                             /* DEST_TYPE field in data is 0 */
   5868                             field_len = soc_mem_field_length(unit, L2Xm, DEST_TYPEf);
   5869                             soc_mem_field32_set(unit, L2Xm, &rep->new_mask, DEST_TYPEf,
   5870                                                 (1 << field_len) - 1);
   5871 
   5872                             field_len = soc_mem_field_length(unit, L2Xm, MODULE_IDf);
   5873                             soc_mem_field32_set(unit, L2Xm, &rep->new_mask,
   5874                                                 MODULE_IDf, (1 << field_len) - 1);
   5875                             soc_mem_field32_set(unit, L2Xm, &rep->new_data,
   5876                                                 MODULE_IDf, rep->new_dest.module);
   5877 
   5878                             field_len = soc_mem_field_length(unit, L2Xm, PORT_NUMf);
   5879                             soc_mem_field32_set(unit, L2Xm, &rep->new_mask,
   5880                                                 PORT_NUMf, (1 << field_len) - 1);
   5881                             soc_mem_field32_set(unit, L2Xm, &rep->new_data,
   5882                                                 PORT_NUMf, rep->new_dest.port);
   5883                         }
   5884                     } /* soc_feature_generic_dest */
   5885                 } else {
   5886                     if (soc_feature(unit, soc_feature_trunk_group_overlay)) {
   5887                         if (rep->new_dest.trunk != -1) {
   5888                             field_len = soc_mem_field_length(unit, L2Xm, DEST_TYPEf);
   5889                             soc_mem_field32_set(unit, L2Xm, &rep->new_mask, DEST_TYPEf,
   5890                                                 (1 << field_len) - 1);
   5891                             soc_mem_field32_set(unit, L2Xm, &rep->new_data, DEST_TYPEf,
   5892                                                 1);
   5893                             /*
   5894                              * Writing to DESTINATION field instead of TGIDf
   5895                              * to ensure the MSB bits of DESTINATION are cleared.
   5896                              */
   5897                             field_len = soc_mem_field_length(unit, L2Xm,
   5898                                     DESTINATIONf);
   5899                             soc_mem_field32_set(unit, L2Xm, &rep->new_mask,
   5900                                     DESTINATIONf, (1 << field_len) - 1);
   5901                             soc_mem_field32_set(unit, L2Xm, &rep->new_data,
   5902                                     DESTINATIONf, rep->new_dest.trunk);
   5903                         } else if (rep->new_dest.port != -1 
   5904                                    && rep->new_dest.module != -1) {
   5905                             /* DEST_TYPE field in data is 0 */
   5906                             field_len = soc_mem_field_length(unit, L2Xm, DEST_TYPEf);
   5907                             soc_mem_field32_set(unit, L2Xm, &rep->new_mask, DEST_TYPEf,
   5908                                                 (1 << field_len) - 1);
   5909                             field_len = soc_mem_field_length(unit, L2Xm, MODULE_IDf);
   5910                             soc_mem_field32_set(unit, L2Xm, &rep->new_mask,
   5911                                                 MODULE_IDf, (1 << field_len) - 1);
   5912                             soc_mem_field32_set(unit, L2Xm, &rep->new_data,
   5913                                                 MODULE_IDf, rep->new_dest.module);
   5914                             field_len = soc_mem_field_length(unit, L2Xm, PORT_NUMf);
   5915                             soc_mem_field32_set(unit, L2Xm, &rep->new_mask,
   5916                                                 PORT_NUMf, (1 << field_len) - 1);
   5917                             soc_mem_field32_set(unit, L2Xm, &rep->new_data,
   5918                                                 PORT_NUMf, rep->new_dest.port);
   5919                         }
   5920                     } else {
   5921                         if (rep->new_dest.trunk != -1) {
   5922                             module = BCM_TRUNK_TO_MODIDf(unit, rep->new_dest.trunk);
   5923                             port = BCM_TRUNK_TO_TGIDf(unit, rep->new_dest.trunk);
   5924                         } else if (rep->new_dest.port != -1 
   5925                                    && rep->new_dest.module != -1) {
   5926                             module = rep->new_dest.module;
   5927                             port = rep->new_dest.port;
   5928                         } else {
   5929                             module = port = -1;
   5930                         }
   5931                         if (module != -1 && port != -1) {
   5932                             field_len = soc_mem_field_length(unit, L2Xm, MODULE_IDf);
   5933                             soc_mem_field32_set(unit, L2Xm, &rep->new_mask, MODULE_IDf,
   5934                                                 (1 << field_len) - 1);
   5935                             soc_mem_field32_set(unit, L2Xm, &rep->new_data, MODULE_IDf,
   5936                                                 module);
   5937                             field_len = soc_mem_field_length(unit, L2Xm, TGID_PORTf);
   5938                             soc_mem_field32_set(unit, L2Xm, &rep->new_mask, TGID_PORTf,
   5939                                                 (1 << field_len) - 1);
   5940                             soc_mem_field32_set(unit, L2Xm, &rep->new_data, TGID_PORTf,
   5941                                                 port);
   5942                         }
   5943                     }
   5944                 }
   5945             }
   5946         }
   5947         if (rep->flags & BCM_L2_REPLACE_DES_HIT_CLEAR) {
   5948             soc_mem_field32_set(unit, L2Xm, &rep->new_mask, HITDAf, 1);
   5949         }
   5950         if (rep->flags & BCM_L2_REPLACE_SRC_HIT_CLEAR) {
   5951             soc_mem_field32_set(unit, L2Xm, &rep->new_mask, HITSAf, 1);
   5952         }
   5953     }
   5954 
   5955     return BCM_E_NONE;
   5956 }
   5957 
   5958 STATIC int
   5959 _soc_l2_sync_mem_cache(int unit, _bcm_l2_replace_t *rep_st)
   5960 {
   5961     uint8 *vmap;
   5962     soc_mem_t mem = L2Xm;
   5963     uint32 *cache, *entry, *match_data, *match_mask;
   5964     uint32 *new_data, *new_mask;
   5965     int index_max, idx, i;
   5966     int entry_dw = soc_mem_entry_words(unit, mem);
   5967     int entry_words = soc_mem_entry_words(unit, mem);
   5968     int copyno = SOC_MEM_BLOCK_ANY(unit, mem);
   5969     soc_field_t vld_fld = VALIDf;
   5970 
   5971     cache = SOC_MEM_STATE(unit, mem).cache[copyno];
   5972     if (cache == NULL) {
   5973         return BCM_E_NONE;
   5974     }
   5975 
   5976     if (soc_feature(unit, soc_feature_base_valid)) {
   5977         vld_fld = BASE_VALIDf;
   5978     }
   5979     vmap = SOC_MEM_STATE(unit, mem).vmap[copyno];
   5980     index_max = soc_mem_index_max(unit, mem);
   5981     for (idx = 0; idx <= index_max; idx++) {
   5982         if (!CACHE_VMAP_TST(vmap, idx)) {
   5983             continue;
   5984         }
   5985         entry = cache + (idx * entry_dw);
   5986         if (!soc_mem_field32_get(unit, mem, entry, vld_fld)) {
   5987             continue;
   5988         }
   5989         if (!soc_mem_field32_get(unit, mem, entry, STATIC_BITf)) {
   5990             continue;
   5991         }
   5992         match_data = (uint32 *)&rep_st->match_data;
   5993         match_mask = (uint32 *)&rep_st->match_mask;
   5994         for (i = 0; i < entry_words; i++) {
   5995             if ((entry[i] ^ match_data[i]) & match_mask[i]) {
   5996                 break;
   5997             }
   5998         }
   5999         if (i != entry_words) {
   6000             continue;
   6001         }
   6002         /* Match found, delete or replace entry */
   6003         LOG_VERBOSE(BSL_LS_SOC_COMMON,
   6004                     (BSL_META_U(unit,
   6005                                 "Match found in L2 bulk cache op: %d\n"), idx));
   6006         if (rep_st->flags & BCM_L2_REPLACE_DELETE) {
   6007             /* Delete op - invalidate the entry */
   6008             CACHE_VMAP_CLR(vmap, idx);
   6009         } else {
   6010             /* Replace op - update entry */
   6011             new_data = (uint32 *)&rep_st->new_data;
   6012             new_mask = (uint32 *)&rep_st->new_mask;
   6013             for (i = 0; i < entry_words; i++) {
   6014                 entry[i] ^= (entry[i] ^ new_data[i]) & new_mask[i];
   6015             }
   6016         }
   6017     }
   6018     return BCM_E_NONE;
   6019 }
   6020 
   6021 STATIC int
   6022 _is_soc_l2_mem_cache_enabled(int unit)
   6023 {
   6024     soc_mem_t mem = L2Xm;
   6025     uint32 *cache;
   6026     int copyno = SOC_MEM_BLOCK_ANY(unit, mem);
   6027     
   6028     cache = SOC_MEM_STATE(unit, mem).cache[copyno];
   6029 
   6030     if (cache == NULL) {
   6031         return FALSE;
   6032     }
   6033 
   6034     return TRUE;
   6035 }
   6036 
   6037 STATIC int
   6038 _bcm_esw_l2_replace(int unit, uint32 flags, uint32 int_flags,
   6039                     bcm_l2_addr_t *match_addr, bcm_module_t new_module,
   6040                     bcm_port_t new_port, bcm_trunk_t new_trunk,
   6041                     bcm_l2_traverse_cb trav_fn, void *user_data)
   6042 {
   6043     uint32              cmp_flags;
   6044     _bcm_l2_replace_t   rep_st;
   6045     _bcm_l2_traverse_t  trav_st;
   6046     _bcm_l2_match_ctrl_t *match_ctrl;
   6047     int                 entry_rd_idx, buf_index, entry_index, do_trav_cb;
   6048     int                 rv = BCM_E_UNAVAIL;
   6049     int                 use_hw_ppa, do_freeze;
   6050     int                 mode;
   6051     l2x_entry_t         l2x_entry, *l2x_entry_ptr;
   6052     bcm_l2_addr_t       l2_addr;
   6053     int tid_is_vp_lag;
   6054     uint32 rval = 0;
   6055     uint32 l2_memwr = 0;
   6056 #if defined(BCM_TRIDENT2_SUPPORT) && defined(INCLUDE_L3)
   6057     source_vp_entry_t svp;
   6058     uint32 etype;
   6059 #endif /* BCM_TRIDENT2_SUPPORT && INCLUDE_L3 */
   6060 #ifdef BCM_TRIDENT3_SUPPORT
   6061     uint32 flow_handle;
   6062 #endif /* BCM_TRIDENT3_SUPPORT */
   6063 
   6064     sal_memset(&rep_st, 0, sizeof(_bcm_l2_replace_t));
   6065     sal_memset(&trav_st, 0, sizeof(_bcm_l2_traverse_t));
   6066 
   6067     rep_st.trav_fn = trav_fn;
   6068     rep_st.user_data = user_data;
   6069     rep_st.flags = flags;
   6070     rep_st.int_flags = int_flags;
   6071     if ((int_flags & _BCM_L2_REPLACE_IGNORE_PORTID) &&
   6072         !(flags & BCM_L2_REPLACE_DELETE) &&
   6073         !(flags & BCM_L2_REPLACE_MATCH_DEST)) {
   6074         return BCM_E_PARAM;
   6075     }
   6076     if (!(flags & (BCM_L2_REPLACE_DELETE | BCM_L2_REPLACE_AGE)) &&
   6077         !(int_flags & _BCM_L2_REPLACE_INT_NO_ACTION)) {
   6078         BCM_IF_ERROR_RETURN(_bcm_l2_replace_dest_setup
   6079                             (unit, new_module, new_port, new_trunk,
   6080                              flags & BCM_L2_REPLACE_NEW_TRUNK,
   6081                              &rep_st.new_dest));
   6082     }
   6083 
   6084     if (match_addr == NULL) {
   6085         if (flags & BCM_L2_REPLACE_VPN_TYPE) {
   6086             rep_st.key_type = 3;  /* VFI Type */
   6087         }
   6088     } else {
   6089         rep_st.key_l2_flags = match_addr->flags;
   6090 
   6091         if (flags & BCM_L2_REPLACE_MATCH_DEST) {
   6092             if (int_flags & _BCM_L2_REPLACE_IGNORE_PORTID) {
   6093                 if (!SOC_MODID_ADDRESSABLE(unit, match_addr->modid)) {
   6094                     return BCM_E_BADID;
   6095                 }
   6096                 rep_st.match_dest.vp = -1;
   6097                 rep_st.match_dest.trunk = -1;
   6098                 rep_st.match_dest.port = -1;
   6099                 rep_st.match_dest.module = match_addr->modid;
   6100             } else {
   6101                 BCM_IF_ERROR_RETURN(_bcm_l2_replace_dest_setup
   6102                                     (unit, match_addr->modid, match_addr->port,
   6103                                      match_addr->tgid,
   6104                                      match_addr->flags & BCM_L2_TRUNK_MEMBER,
   6105                                      &rep_st.match_dest));
   6106             }
   6107             if (rep_st.match_dest.vp != -1) {
   6108                 if(match_addr->flags & BCM_L2_TRUNK_MEMBER) {
   6109                     BCM_IF_ERROR_RETURN(
   6110                         _bcm_esw_trunk_id_is_vp_lag(unit, match_addr->tgid,
   6111                                                     &tid_is_vp_lag));
   6112                     if (tid_is_vp_lag) {
   6113 #if defined(BCM_TRIDENT2_SUPPORT) && defined(INCLUDE_L3)
   6114                         if (soc_feature(unit, soc_feature_vp_lag)) {
   6115                             BCM_IF_ERROR_RETURN(
   6116                                 soc_mem_read(unit, SOURCE_VPm, MEM_BLOCK_ANY, 
   6117                                              rep_st.match_dest.vp, &svp));
   6118                             if (SOC_MEM_FIELD_VALID(unit, 
   6119                                                     SOURCE_VPm, ENTRY_TYPEf)) {
   6120                                 etype = soc_SOURCE_VPm_field32_get(unit, &svp, 
   6121                                                                    ENTRY_TYPEf);
   6122                                 switch(etype) {
   6123                                 case 1: /* VPLS SVP and use VFI */
   6124                                     rep_st.key_type =  3; /* VFI */
   6125                                     break;
   6126                                 case 3: /* VLAN-based Forwarding */
   6127                                     rep_st.key_type =  0; /* L2 Bridge */
   6128                                     break;
   6129                                 default: /* 0: INVALID */
   6130                                     rep_st.key_type = -1; /* Do not care key type */
   6131                                     break;
   6132                                 }
   6133                             }
   6134                         } else 
   6135 #endif /* BCM_TRIDENT2_SUPPORT && INCLUDE_L3 */
   6136                         {
   6137                             return BCM_E_PORT;
   6138                         }
   6139                     } else {
   6140                         return BCM_E_PARAM;
   6141                     }
   6142                 } else {
   6143                     if (!BCM_GPORT_IS_WLAN_PORT(match_addr->port)  &&
   6144                         !BCM_GPORT_IS_NIV_PORT(match_addr->port)   &&
   6145                         !BCM_GPORT_IS_TRILL_PORT(match_addr->port) &&
   6146                         !BCM_GPORT_IS_VLAN_PORT(match_addr->port)  &&
   6147                         !BCM_GPORT_IS_EXTENDER_PORT(match_addr->port)) {
   6148                          /* Note: For MPLS, MiM, L2GRE, VXLAN VFI types only */
   6149                          rep_st.key_type = 3; /* VFI Type */
   6150                     }
   6151                 }
   6152             }
   6153         }
   6154 
   6155         if (flags & BCM_L2_REPLACE_MATCH_VLAN) {
   6156             rep_st.key_vfi = -1;
   6157 #ifdef BCM_TRIUMPH_SUPPORT
   6158             if (SOC_MEM_IS_VALID(unit, VFIm)) {
   6159                 if (_BCM_VPN_VFI_IS_SET(match_addr->vid)) {
   6160                     _BCM_VPN_GET(rep_st.key_vfi, _BCM_VPN_TYPE_VFI, match_addr->vid);
   6161                 }
   6162             }
   6163 #endif /* BCM_TRIUMPH_SUPPORT */
   6164             if (rep_st.key_vfi != -1) {
   6165                 if (rep_st.key_vfi > soc_mem_index_max(unit, VFIm)) {
   6166                     return BCM_E_PARAM;
   6167                 }
   6168                 rep_st.key_type = 3;  /* VFI Type */
   6169             } else {
   6170                 VLAN_CHK_ID(unit, match_addr->vid);
   6171                 rep_st.key_vlan = match_addr->vid;
   6172                 rep_st.key_type = 0;  /* L2 Bridge */
   6173             }
   6174         }
   6175 
   6176         if (flags & BCM_L2_REPLACE_MATCH_MAC) {
   6177             sal_memcpy(&rep_st.key_mac, match_addr->mac, sizeof(bcm_mac_t));
   6178         }
   6179 
   6180         /* When replace L2 by MAC, key type must be provided. */
   6181             /* Key type is 0 by default for L2 Bridge. */
   6182             /* Here add support for explicitly assigned VFI type */
   6183         if (flags & BCM_L2_REPLACE_VPN_TYPE) {
   6184             rep_st.key_type = 3;  /* VFI Type */
   6185         }
   6186 #ifdef BCM_TRIDENT2PLUS_SUPPORT
   6187         if (SOC_IS_TRIDENT2PLUS(unit) || SOC_IS_TRIDENT3X(unit)) {
   6188             if (flags & BCM_L2_REPLACE_MATCH_INT_PRI) {
   6189                 rep_st.key_int_pri = match_addr->cos_dst;
   6190             }
   6191             if (flags & BCM_L2_REPLACE_MATCH_CLASS_ID) {
   6192                 rep_st.key_class_id= match_addr->group;
   6193             }
   6194         }
   6195 #endif
   6196     }
   6197 #ifdef BCM_TRIDENT3_SUPPORT
   6198     if (match_addr != NULL) {
   6199         flow_handle = match_addr->flow_handle;
   6200     }
   6201     else {
   6202         flow_handle = 0;
   6203     }
   6204 
   6205     if (soc_feature(unit, soc_feature_flex_flow) &&
   6206         flow_handle != 0) {
   6207 
   6208         /* Get view id corresponding to the specified flow. */
   6209         rv = soc_flow_db_ffo_to_mem_view_id_get(unit,
   6210                               match_addr->flow_handle,
   6211                               match_addr->flow_option_handle,
   6212                               SOC_FLOW_DB_FUNC_L2_SWITCH_ID,
   6213                               &rep_st.view_id);
   6214         BCM_IF_ERROR_RETURN(rv);
   6215 
   6216         BCM_IF_ERROR_RETURN(_bcm_td3_flex_l2_replace_data_mask_setup(unit, &rep_st));
   6217     }
   6218     else
   6219 #endif
   6220     {
   6221         BCM_IF_ERROR_RETURN(_bcm_l2_replace_data_mask_setup(unit, &rep_st));
   6222     }
   6223 
   6224     /* Validate matching destination only if match all was not set */
   6225     cmp_flags = flags & (BCM_L2_REPLACE_MATCH_MAC | BCM_L2_REPLACE_MATCH_VLAN |
   6226                          BCM_L2_REPLACE_MATCH_DEST);
   6227     use_hw_ppa = TRUE;
   6228     switch (cmp_flags) {
   6229     case BCM_L2_REPLACE_MATCH_MAC:
   6230     case BCM_L2_REPLACE_MATCH_MAC | BCM_L2_REPLACE_MATCH_DEST:
   6231     case BCM_L2_REPLACE_MATCH_MAC | BCM_L2_REPLACE_MATCH_VLAN:
   6232         if (!soc_feature(unit, soc_feature_l2_bulk_control)) {
   6233             use_hw_ppa = FALSE;
   6234         } else if (soc_feature(unit, soc_feature_l2_bulk_bypass_replace)) {
   6235             if (!( flags & (BCM_L2_REPLACE_DELETE | BCM_L2_REPLACE_AGE)) &&
   6236                 !(int_flags & _BCM_L2_REPLACE_INT_NO_ACTION)) {
   6237                 use_hw_ppa = FALSE;
   6238             }
   6239         }
   6240         break;
   6241     case BCM_L2_REPLACE_MATCH_VLAN:
   6242     case BCM_L2_REPLACE_MATCH_DEST:
   6243     case BCM_L2_REPLACE_MATCH_VLAN | BCM_L2_REPLACE_MATCH_DEST:
   6244         if (SOC_CONTROL(unit)->l2x_ppa_bypass) {
   6245             use_hw_ppa = FALSE;
   6246         } else if (!soc_feature(unit, soc_feature_l2_bulk_control) &&
   6247                    !soc_feature(unit, soc_feature_ppa_match_vp) &&
   6248                    (rep_st.flags & BCM_L2_REPLACE_MATCH_DEST) &&
   6249                    rep_st.match_dest.vp != -1) {
   6250             use_hw_ppa = FALSE;
   6251         } else if (soc_feature(unit, soc_feature_l2_bulk_bypass_replace)) {
   6252             if (!(flags & (BCM_L2_REPLACE_DELETE | BCM_L2_REPLACE_AGE)) &&
   6253                 !(int_flags & _BCM_L2_REPLACE_INT_NO_ACTION)) {
   6254                 if (cmp_flags != BCM_L2_REPLACE_MATCH_DEST ||
   6255                     rep_st.match_dest.vp != -1 ||
   6256                     rep_st.match_dest.trunk != -1) {
   6257                     use_hw_ppa = FALSE;
   6258                 }
   6259             }
   6260         } else if (!soc_feature(unit, soc_feature_l2_bulk_control) &&
   6261             (flags & BCM_L2_REPLACE_SRC_HIT_CLEAR || 
   6262              flags & BCM_L2_REPLACE_DES_HIT_CLEAR)) {
   6263             /*
   6264               * For devices without supporting L2 bulk feature:
   6265               * - It doesn't support to reset SRC/DST Hit-bit respectively by Hardware L2 PPA
   6266               * register for L2 replace function.
   6267               * - To traverse the L2 table and replace given entry if any L2 entry matches.
   6268               */
   6269             use_hw_ppa = FALSE;
   6270         }
   6271         break;
   6272     default:
   6273         break;
   6274     }
   6275 #ifdef PLISIM
   6276 #if defined(BCM_KATANA_SUPPORT)
   6277     /* Forcefully setting hw_ppa flag to false in KatanaSimulationEnvironment */
   6278     if (SOC_IS_KATANAX(unit) && (SAL_BOOT_PLISIM || SAL_BOOT_BCMSIM)) {
   6279         use_hw_ppa = FALSE;
   6280     }
   6281 #endif
   6282 #endif
   6283 
   6284     /* Hardware L2 PPA register don't support to delete by UC, MC entries or both respectively */
   6285     if (use_hw_ppa && 
   6286         (flags & BCM_L2_REPLACE_DELETE) && 
   6287         (flags & (BCM_L2_REPLACE_MATCH_UC | BCM_L2_REPLACE_MATCH_MC))) {
   6288         if (SOC_REG_IS_VALID(unit, PER_PORT_AGE_CONTROLr) || 
   6289             SOC_REG_IS_VALID(unit, PER_PORT_AGE_CONTROL_64r)) {
   6290             return BCM_E_UNAVAIL;
   6291         }
   6292     }
   6293 
   6294     mode = SOC_CONTROL(unit)->l2x_mode;
   6295     /* Delete operation don't require freeze */
   6296     do_freeze = FALSE;
   6297     if (use_hw_ppa && (int_flags & _BCM_L2_REPLACE_INT_NO_ACTION)) {
   6298         if (soc_feature(unit, soc_feature_l2_bulk_control) &&
   6299             mode == L2MODE_FIFO) {
   6300             _bcm_l2_match_ctrl[unit]->entry_wr_idx = 0;
   6301         } else {
   6302             use_hw_ppa = FALSE;
   6303         }
   6304     } else if ((!use_hw_ppa &&
   6305                 !(flags & (BCM_L2_REPLACE_DELETE | BCM_L2_REPLACE_AGE))) || 
   6306                mode != L2MODE_FIFO || 
   6307                ((flags & BCM_L2_REPLACE_MATCH_STATIC) &&
   6308                 _is_soc_l2_mem_cache_enabled(unit))) {
   6309         do_freeze = TRUE;
   6310     }
   6311 
   6312     if (do_freeze) {
   6313         BCM_IF_ERROR_RETURN(bcm_esw_l2_addr_freeze(unit));
   6314     }
   6315     if (use_hw_ppa) {
   6316         rv = _bcm_l2_replace_by_hw(unit, flags, &rep_st);
   6317         if (BCM_SUCCESS(rv) && (int_flags & _BCM_L2_REPLACE_INT_NO_ACTION)) {
   6318             match_ctrl = _bcm_l2_match_ctrl[unit];
   6319             if (SOC_REG_IS_VALID(unit,L2_MOD_FIFO_ENABLEr)) {
   6320                 rv = READ_L2_MOD_FIFO_ENABLEr(unit, &rval);
   6321                 l2_memwr = soc_reg_field_get(unit, L2_MOD_FIFO_ENABLEr, rval,
   6322                                              L2_MEMWRf);
   6323                 if (BCM_SUCCESS(rv)) {
   6324                     rv = soc_reg_field32_modify(unit, L2_MOD_FIFO_ENABLEr,
   6325                                      REG_PORT_ANY, L2_MEMWRf, 1);
   6326                 }
   6327             } else {
   6328                 rv = READ_AUX_ARB_CONTROLr(unit, &rval);
   6329                 l2_memwr = soc_reg_field_get(unit, AUX_ARB_CONTROLr, rval,
   6330                                              L2_MOD_FIFO_ENABLE_MEMWRf);
   6331                 if (BCM_SUCCESS(rv)) {
   6332                     rv = soc_reg_field32_modify(unit, AUX_ARB_CONTROLr,REG_PORT_ANY,
   6333                                             L2_MOD_FIFO_ENABLE_MEMWRf, 1);
   6334                 }
   6335             }
   6336             if (BCM_SUCCESS(rv)) {
   6337                 rv = soc_mem_read(unit, L2Xm, MEM_BLOCK_ANY, 0, &l2x_entry);
   6338                 if (BCM_SUCCESS(rv)) {
   6339                     (void)soc_mem_write(unit, L2Xm, MEM_BLOCK_ALL, 0,
   6340                                         &l2x_entry);
   6341                 }
   6342                 if (SOC_REG_IS_VALID(unit,L2_MOD_FIFO_ENABLEr)) {
   6343                     (void)soc_reg_field32_modify(unit, L2_MOD_FIFO_ENABLEr,
   6344                                  REG_PORT_ANY, L2_MEMWRf, l2_memwr);
   6345                 } else {
   6346                     (void)soc_reg_field32_modify(unit, AUX_ARB_CONTROLr,
   6347                                              REG_PORT_ANY,
   6348                                              L2_MOD_FIFO_ENABLE_MEMWRf, l2_memwr);
   6349                 }
   6350             }
   6351             entry_rd_idx = 0;
   6352             do_trav_cb = TRUE;
   6353             while (1) {
   6354                 if (entry_rd_idx == match_ctrl->entry_wr_idx) {
   6355                     if (sal_sem_take(_bcm_l2_match_ctrl[unit]->sem, 5000000)) {
   6356                         /* If waiting too long, something happened in HW */
   6357                         if (SOC_CONTROL(unit)->l2x_pid == SAL_THREAD_ERROR) {
   6358                             for (buf_index = entry_rd_idx / _BCM_L2_MATCH_ENTRY_BUF_SIZE;
   6359                                  buf_index >= 0;
   6360                                  buf_index --) {
   6361                                 sal_free(match_ctrl->l2x_entry_buf[buf_index]);
   6362                             }
   6363                         }
   6364                         rv = BCM_E_INTERNAL;
   6365                         break;
   6366                     }
   6367 
   6368                     continue;                
   6369                 }
   6370                 buf_index = entry_rd_idx / _BCM_L2_MATCH_ENTRY_BUF_SIZE;
   6371                 entry_index = entry_rd_idx % _BCM_L2_MATCH_ENTRY_BUF_SIZE;
   6372                 l2x_entry_ptr =
   6373                     &match_ctrl->l2x_entry_buf[buf_index][entry_index];
   6374 
   6375                 if (l2x_entry_ptr->entry_data[0] == 0) {
   6376                     for (; buf_index >= 0; buf_index--) {
   6377                         sal_free(match_ctrl->l2x_entry_buf[buf_index]);
   6378                     }
   6379                     break;
   6380                 }
   6381                 if (do_trav_cb) {
   6382                     (void)_bcm_esw_l2_from_l2x(unit, 0, &l2_addr,
   6383                                                (uint32 *)l2x_entry_ptr);
   6384                     if (trav_fn(unit, &l2_addr, user_data) < 0) {
   6385                         do_trav_cb = FALSE;
   6386                     }
   6387                 }
   6388                 if (do_trav_cb) {
   6389                     entry_rd_idx++;
   6390                 } else {
   6391                     /* skip to the last buffered entry */
   6392                     entry_rd_idx = match_ctrl->entry_wr_idx - 1;
   6393                 }
   6394             }
   6395         }
   6396     } else {
   6397         trav_st.user_data = (void *)&rep_st;
   6398         trav_st.int_cb = _bcm_l2_entry_replace;
   6399         rv = _bcm_esw_l2_traverse(unit, &trav_st);
   6400     }
   6401 
   6402     if (use_hw_ppa && !(int_flags & _BCM_L2_REPLACE_INT_NO_ACTION) &&
   6403         SOC_SUCCESS(rv) && (rep_st.flags & BCM_L2_REPLACE_MATCH_STATIC)) {
   6404         /* update the entries in mem cache with the bulk op results */
   6405         rv = _soc_l2_sync_mem_cache(unit, &rep_st);
   6406     }
   6407 
   6408     if (do_freeze) {
   6409         BCM_IF_ERROR_RETURN(bcm_esw_l2_addr_thaw(unit));
   6410     }
   6411 
   6412     return rv;
   6413 }
   6414 
   6415 /*
   6416  * Function:
   6417  *     bcm_esw_l2_replace
   6418  * Description:
   6419  *     To replace destination (or delete) multiple L2 entries
   6420  * Parameters:
   6421  *     unit         device number
   6422  *     flags        flags BCM_L2_REPLACE_*
   6423  *     match_addr   L2 parameters to match on delete/replace
   6424  *     new_module   new module ID for a replace
   6425  *     new_port     new port for a replace
   6426  *     new_trunk    new trunk for a replace
   6427  * Return:
   6428  *     BCM_E_XXX
   6429  */
   6430 int
   6431 bcm_esw_l2_replace(int unit, uint32 flags, bcm_l2_addr_t *match_addr,
   6432                    bcm_module_t new_module, bcm_port_t new_port,
   6433                    bcm_trunk_t new_trunk)
   6434 {
   6435 #if defined(BCM_TOMAHAWK3_SUPPORT)
   6436     /* Added to handle SDK functions calling esw version,
   6437      * instead of Tomahawk3's version
   6438      */
   6439     if (SOC_IS_TOMAHAWK3(unit)) {
   6440         return bcm_tomahawk3_l2_replace(unit, flags, match_addr, new_module,
   6441                                         new_port, new_trunk);
   6442     }
   6443 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   6444 
   6445     L2_INIT(unit);
   6446 
   6447 #if defined(BCM_TRIUMPH3_SUPPORT)
   6448     if (soc_feature(unit, soc_feature_ism_memory)) {
   6449         return bcm_tr3_l2_replace(unit, flags, match_addr,
   6450                                   new_module, new_port, new_trunk);
   6451     }
   6452 #endif /* BCM_TRIUMPH3_SUPPORT */    
   6453 
   6454     if (!flags) {
   6455         return BCM_E_PARAM;
   6456     }
   6457     if (( flags & (BCM_L2_REPLACE_DELETE | BCM_L2_REPLACE_AGE) ) &&
   6458         (flags & BCM_L2_REPLACE_NEW_TRUNK)) {
   6459         return BCM_E_PARAM;
   6460     }
   6461 
   6462     if ((flags & BCM_L2_REPLACE_DELETE) && (flags & BCM_L2_REPLACE_MATCH_MAC) &&
   6463         ((flags & BCM_L2_REPLACE_MATCH_UC) || (flags & BCM_L2_REPLACE_MATCH_MC))) {
   6464         return BCM_E_PARAM;
   6465     }
   6466 
   6467     if (flags & BCM_L2_REPLACE_AGE) {
   6468         if (!soc_feature(unit, soc_feature_l2_bulk_control)) {
   6469             return BCM_E_PARAM;
   6470         }
   6471     }
   6472 
   6473     /* matching L2 address allowed to be NULL together with */
   6474     /* BCM_L2_REPLACE_DELETE flag indicating to delete all entries. */
   6475     if (NULL == match_addr) {
   6476         if (!(flags & (BCM_L2_REPLACE_DELETE | BCM_L2_REPLACE_AGE) ) && 
   6477             !(flags & (BCM_L2_REPLACE_SRC_HIT_CLEAR | BCM_L2_REPLACE_DES_HIT_CLEAR))) {
   6478             return BCM_E_PARAM;
   6479         }
   6480         flags &= ~(BCM_L2_REPLACE_MATCH_VLAN | BCM_L2_REPLACE_MATCH_MAC |
   6481                    BCM_L2_REPLACE_MATCH_DEST);
   6482 
   6483         if (flags & BCM_L2_REPLACE_VLAN_AND_VPN_TYPE) {
   6484             BCM_IF_ERROR_RETURN
   6485                 (_bcm_esw_l2_replace(unit, flags, 0, match_addr, new_module,
   6486                                      new_port, new_trunk, NULL, NULL));
   6487             flags ^= BCM_L2_REPLACE_VPN_TYPE;
   6488         }
   6489     }
   6490     /* coverity[var_deref_op : FALSE] */
   6491     /* coverity[var_deref_model : FALSE] */
   6492     return _bcm_esw_l2_replace(unit, flags, 0, match_addr, new_module,
   6493                                new_port, new_trunk, NULL, NULL);
   6494 }
   6495 
   6496 int 
   6497 bcm_esw_l2_matched_traverse(int unit, uint32 flags, bcm_l2_addr_t *match_addr, 
   6498                             bcm_l2_traverse_cb trav_fn, void *user_data)
   6499 {
   6500     uint32 replace_flags, int_flags;
   6501 
   6502 #if defined(BCM_TOMAHAWK3_SUPPORT)
   6503     /* Added to handle SDK functions calling esw version,
   6504      * instead of Tomahawk3's version
   6505      */
   6506     if (SOC_IS_TOMAHAWK3(unit)) {
   6507         return bcm_tomahawk3_l2_matched_traverse(unit, flags, match_addr,
   6508                                                  trav_fn, user_data);
   6509     }
   6510 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   6511 
   6512     if (soc_feature(unit, soc_feature_ism_memory)) {
   6513         return _bcm_esw_l2_matched_traverse(unit, flags, match_addr, trav_fn,
   6514                                             user_data);
   6515     }
   6516 
   6517     if (!trav_fn) {
   6518         return BCM_E_PARAM;
   6519     }
   6520 
   6521     if (!match_addr) {
   6522         return BCM_E_PARAM;
   6523     }
   6524 
   6525     replace_flags = 0;
   6526     int_flags = _BCM_L2_REPLACE_INT_NO_ACTION;
   6527     /*
   6528     * 1/ If BCM_L2_TRAVERSE_MATCH_DYNAMIC and BCM_L2_TRAVERSE_MATCH_STATIC 
   6529     *     are passed simultaneously to API bcm_l2_matched_traverse, 
   6530     *     this API will match all entries.
   6531     * 2/ If both BCM_L2_TRAVERSE_MATCH_DYNAMIC and BCM_L2_TRAVERSE_MATCH_STATIC 
   6532     *     are not passed to API bcm_l2_matched_traverse,
   6533     *     this API will also match all entries as before. This is the legacy behavior.
   6534     * 3/  If only BCM_L2_TRAVERSE_MATCH_DYNAMIC is passed to 
   6535     *     API bcm_l2_matched_traverse, this API will only match dynamic entries.
   6536     * 4/ If only BCM_L2_TRAVERSE_MATCH_STATIC is passed to 
   6537     *     API bcm_l2_matched_traverse, this API will only match static entries.  
   6538     */
   6539     if (((flags & BCM_L2_TRAVERSE_MATCH_STATIC)?1:0) ==
   6540         ((flags & BCM_L2_TRAVERSE_MATCH_DYNAMIC)?1:0)) {
   6541         /* BCM_L2_REPLACE_MATCH_STATIC means to replace static as well as
   6542        * non-static entries */
   6543         replace_flags |= BCM_L2_REPLACE_MATCH_STATIC;
   6544     }
   6545     if (flags & BCM_L2_TRAVERSE_MATCH_MAC) {
   6546         replace_flags |= BCM_L2_REPLACE_MATCH_MAC;
   6547     }
   6548     if (flags & BCM_L2_TRAVERSE_MATCH_VLAN) {
   6549         replace_flags |= BCM_L2_REPLACE_MATCH_VLAN;
   6550     }
   6551     if (flags & BCM_L2_TRAVERSE_MATCH_DEST) {
   6552         replace_flags |= BCM_L2_REPLACE_MATCH_DEST;
   6553     }
   6554     if (!(flags & BCM_L2_TRAVERSE_IGNORE_DISCARD_SRC)) {
   6555         int_flags |= _BCM_L2_REPLACE_INT_MATCH_DISCARD_SRC;
   6556     }
   6557     if (!(flags & BCM_L2_TRAVERSE_IGNORE_DES_HIT)) {
   6558         int_flags |= _BCM_L2_REPLACE_INT_MATCH_DES_HIT;
   6559     }
   6560     if (!(flags & BCM_L2_TRAVERSE_IGNORE_SRC_HIT)) {
   6561         int_flags |= _BCM_L2_REPLACE_INT_MATCH_SRC_HIT;
   6562     }
   6563     if (flags & BCM_L2_TRAVERSE_MATCH_NATIVE) {
   6564         int_flags |= _BCM_L2_REPLACE_INT_MATCH_NATIVE;
   6565     }
   6566 
   6567     if ((flags & BCM_L2_TRAVERSE_MATCH_STATIC) && 
   6568          !(flags & BCM_L2_TRAVERSE_MATCH_DYNAMIC)){
   6569         int_flags |= _BCM_L2_REPLACE_INT_MATCH_ONLY_STATIC;
   6570     }
   6571 
   6572     return _bcm_esw_l2_replace(unit, replace_flags, int_flags, match_addr, 0,
   6573                                0, 0, trav_fn, user_data);
   6574 }
   6575 
   6576 /*
   6577  * Function:
   6578  *     bcm_esw_l2_station_add
   6579  * Description:
   6580  *     Add an entry to L2 Station Table      
   6581  * Parameters:
   6582  *     unit         - (IN) BCM device number
   6583  *     station_id   - (IN/OUT) Station ID
   6584  *     station      - (IN) Pointer to station address information
   6585  * Return:
   6586  *     BCM_E_XXX
   6587  */
   6588 int
   6589 bcm_esw_l2_station_add(int unit, int *station_id, bcm_l2_station_t *station)
   6590 {
   6591     int rv = BCM_E_UNAVAIL;
   6592 
   6593 #if defined(BCM_TOMAHAWK3_SUPPORT)
   6594     /* Added to handle SDK functions calling esw version,
   6595      * instead of Tomahawk3's version
   6596      */
   6597     if (SOC_IS_TOMAHAWK3(unit)) {
   6598         return bcm_tomahawk3_l2_station_add(unit, station_id, station);
   6599     }
   6600 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   6601 
   6602 
   6603 #if defined(BCM_TRIUMPH_SUPPORT)
   6604     if (SOC_IS_TRIDENT(unit) || SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit)
   6605         || SOC_IS_KATANAX(unit) || SOC_IS_TRIUMPH3(unit) ||  SOC_IS_TRIDENT3X(unit)
   6606         || soc_feature(unit, soc_feature_gh2_my_station)) {
   6607         rv = bcm_tr_l2_station_add(unit, station_id, station);
   6608     }
   6609 #endif
   6610 
   6611     return (rv);
   6612 }
   6613 
   6614 /*
   6615  * Function:
   6616  *     bcm_esw_l2_station_delete
   6617  * Description:
   6618  *     Delete an entry from L2 Station Table
   6619  * Parameters:
   6620  *     unit         - (IN) BCM device number
   6621  *     station_id   - (IN) Station ID
   6622  * Return:
   6623  *     BCM_E_XXX
   6624  */
   6625 int
   6626 bcm_esw_l2_station_delete(int unit, int station_id)
   6627 {
   6628 
   6629     int rv = BCM_E_UNAVAIL;
   6630 
   6631 #if defined(BCM_TOMAHAWK3_SUPPORT)
   6632     /* Added to handle SDK functions calling esw version,
   6633      * instead of Tomahawk3's version
   6634      */
   6635     if (SOC_IS_TOMAHAWK3(unit)) {
   6636         return bcm_tomahawk3_l2_station_delete(unit, station_id);
   6637     }
   6638 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   6639 
   6640 #if defined(BCM_TRIUMPH_SUPPORT)
   6641     if (SOC_IS_TRIDENT(unit) || SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit)
   6642         || SOC_IS_KATANAX(unit) || SOC_IS_TRIUMPH3(unit) || SOC_IS_TRIDENT3X(unit)
   6643         || soc_feature(unit, soc_feature_gh2_my_station)) {
   6644         rv = bcm_tr_l2_station_delete(unit, station_id);
   6645     }
   6646 #endif
   6647     return (rv);
   6648 }
   6649 
   6650 /*
   6651  * Function:
   6652  *     bcm_esw_l2_station_delete_all
   6653  * Description:
   6654  *     Clear all L2 Station Table entries
   6655  * Parameters:
   6656  *     unit - (IN) BCM device number
   6657  * Return:
   6658  *     BCM_E_XXX
   6659  */
   6660 int
   6661 bcm_esw_l2_station_delete_all(int unit)
   6662 {
   6663     int rv = BCM_E_UNAVAIL;
   6664 
   6665 #if defined(BCM_TOMAHAWK3_SUPPORT)
   6666     /* Added to handle SDK functions calling esw version,
   6667      * instead of Tomahawk3's version
   6668      */
   6669     if (SOC_IS_TOMAHAWK3(unit)) {
   6670         return bcm_tomahawk3_l2_station_delete_all(unit);
   6671     }
   6672 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   6673 
   6674 #if defined(BCM_TRIUMPH_SUPPORT)
   6675     if (SOC_IS_TRIDENT(unit) || SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit)
   6676         || SOC_IS_KATANAX(unit) || SOC_IS_TRIUMPH3(unit) || SOC_IS_TRIDENT3X(unit)
   6677         || soc_feature(unit, soc_feature_gh2_my_station)) {
   6678         rv = bcm_tr_l2_station_delete_all(unit);
   6679     }
   6680 #endif
   6681 
   6682     return (rv);
   6683 }
   6684 
   6685 /*
   6686  * Function:
   6687  *     bcm_esw_l2_station_get
   6688  * Description:
   6689  *     Get L2 station entry detail from Station Table
   6690  * Parameters:
   6691  *     unit         - (IN) BCM device number
   6692  *     station_id   - (IN) Station ID
   6693  *     station      - (OUT) Pointer to station address information.
   6694  * Return:
   6695  *     BCM_E_XXX
   6696  */
   6697 int
   6698 bcm_esw_l2_station_get(int unit, int station_id, bcm_l2_station_t *station)
   6699 {
   6700     int rv = BCM_E_UNAVAIL;
   6701 
   6702 #if defined(BCM_TOMAHAWK3_SUPPORT)
   6703     /* Added to handle SDK functions calling esw version,
   6704      * instead of Tomahawk3's version
   6705      */
   6706     if (SOC_IS_TOMAHAWK3(unit)) {
   6707         return bcm_tomahawk3_l2_station_get(unit, station_id, station);
   6708     }
   6709 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   6710 
   6711 #if defined(BCM_TRIUMPH_SUPPORT)
   6712     if (SOC_IS_TRIDENT(unit) || SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit)
   6713         || SOC_IS_KATANAX(unit) || SOC_IS_TRIUMPH3(unit) || SOC_IS_TRIDENT3X(unit)
   6714         || soc_feature(unit, soc_feature_gh2_my_station)) {
   6715         rv = bcm_tr_l2_station_get(unit, station_id, station);
   6716     }
   6717 #endif
   6718 
   6719     return (rv);
   6720 }
   6721 
   6722 /*
   6723  * Function:
   6724  *     bcm_esw_l2_station_size_get
   6725  * Description:
   6726  *     Get size of L2 Station Table
   6727  * Parameters:
   6728  *     unit - (IN) BCM device number
   6729  *     size - (OUT) L2 Station table size
   6730  * Return:
   6731  *     BCM_E_XXX
   6732  */
   6733 int
   6734 bcm_esw_l2_station_size_get(int unit, int *size)
   6735 {
   6736     int rv = BCM_E_UNAVAIL;
   6737 
   6738 #if defined(BCM_TOMAHAWK3_SUPPORT)
   6739     /* Added to handle SDK functions calling esw version,
   6740      * instead of Tomahawk3's version
   6741      */
   6742     if (SOC_IS_TOMAHAWK3(unit)) {
   6743         return bcm_tomahawk3_l2_station_size_get(unit, size);
   6744     }
   6745 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   6746 
   6747 #if defined(BCM_TRIUMPH_SUPPORT)
   6748     if (SOC_IS_TRIDENT(unit) || SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit)
   6749         || SOC_IS_KATANAX(unit) || SOC_IS_TRIUMPH3(unit) || SOC_IS_TRIDENT3X(unit)
   6750         || soc_feature(unit, soc_feature_gh2_my_station)) {
   6751         rv = bcm_tr_l2_station_size_get(unit, size);
   6752     }
   6753 #endif
   6754 
   6755     return (rv);
   6756 }
   6757 
   6758 /*
   6759  * Function:
   6760  *     bcm_esw_l2_station_traverse
   6761  * Description:
   6762  *     Traverse L2 station entry from Station Table
   6763  * Parameters:
   6764  *     unit         - (IN) BCM device number
   6765  *     trav_fn   -  (IN) Customer defines function is used to traverse
   6766  *     user_data - (IN) Pointer to information of customer.
   6767  * Return:
   6768  *     BCM_E_XXX
   6769  */
   6770 int 
   6771 bcm_esw_l2_station_traverse(int unit, bcm_l2_station_traverse_cb trav_fn, void *user_data)
   6772 {
   6773     int rv = BCM_E_UNAVAIL;
   6774 
   6775 #if defined(BCM_TOMAHAWK3_SUPPORT)
   6776     /* Added to handle SDK functions calling esw version,
   6777      * instead of Tomahawk3's version
   6778      */
   6779     if (SOC_IS_TOMAHAWK3(unit)) {
   6780         return bcm_tomahawk3_l2_station_traverse(unit, trav_fn, user_data);
   6781     }
   6782 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   6783 
   6784 #if defined(BCM_TRIUMPH_SUPPORT)
   6785     if (SOC_IS_TRIDENT(unit) || SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit)
   6786         || SOC_IS_KATANAX(unit) || SOC_IS_TRIUMPH3(unit) || SOC_IS_TRIDENT3X(unit)
   6787         || soc_feature(unit, soc_feature_gh2_my_station)) {
   6788         rv = bcm_tr_l2_station_traverse(unit, trav_fn, user_data);
   6789     }
   6790 #endif
   6791 
   6792     return (rv);
   6793 }
   6794 
   6795 int
   6796 bcm_esw_l2_ring_replace( int unit, bcm_l2_ring_t *l2_ring)
   6797 {
   6798     int rv = BCM_E_UNAVAIL;
   6799 
   6800 #if defined(BCM_TRIUMPH3_SUPPORT) || defined(BCM_KATANA2_SUPPORT)
   6801     if (soc_feature(unit, soc_feature_failover) &&
   6802         (SOC_IS_TRIUMPH3(unit) || SOC_IS_KATANA2(unit))) {
   6803          return bcm_tr3_l2_ring_replace(unit, l2_ring);
   6804     }
   6805 #endif
   6806 
   6807     return rv;
   6808 }
   6809 
   6810 /*
   6811  * Function:
   6812  *     bcm_esw_l2_mac_port_create
   6813  * Description:
   6814  *     Create a MAC port.
   6815  * Parameters:
   6816  *     unit - (IN) BCM device number
   6817  *     mac_port - (IN/OUT) MAC port info
   6818  * Return:
   6819  *     BCM_E_XXX
   6820  */
   6821 int
   6822 bcm_esw_l2_mac_port_create(int unit, bcm_l2_mac_port_t *mac_port)
   6823 {
   6824     return BCM_E_UNAVAIL;
   6825 }
   6826 
   6827 /*
   6828  * Function:
   6829  *     bcm_esw_l2_mac_port_destroy
   6830  * Description:
   6831  *     Destroy a MAC port.
   6832  * Parameters:
   6833  *     unit - (IN) BCM device number
   6834  *     mac_port_id - (IN) MAC port GPORT ID
   6835  * Return:
   6836  *     BCM_E_XXX
   6837  */
   6838 int
   6839 bcm_esw_l2_mac_port_destroy(int unit, bcm_gport_t mac_port_id)
   6840 {
   6841     return BCM_E_UNAVAIL;
   6842 }
   6843 
   6844 /*
   6845  * Function:
   6846  *     bcm_esw_l2_mac_port_destroy_all
   6847  * Description:
   6848  *     Destroy all MAC ports.
   6849  * Parameters:
   6850  *     unit - (IN) BCM device number
   6851  * Return:
   6852  *     BCM_E_XXX
   6853  */
   6854 int
   6855 bcm_esw_l2_mac_port_destroy_all(int unit)
   6856 {
   6857     return BCM_E_UNAVAIL;
   6858 }
   6859 
   6860 /*
   6861  * Function:
   6862  *     bcm_esw_l2_mac_port_get
   6863  * Description:
   6864  *     Get info about a MAC port.
   6865  * Parameters:
   6866  *     unit - (IN) BCM device number
   6867  *     mac_port - (IN/OUT) MAC port info
   6868  * Return:
   6869  *     BCM_E_XXX
   6870  */
   6871 int
   6872 bcm_esw_l2_mac_port_get(int unit, bcm_l2_mac_port_t *mac_port)
   6873 {
   6874     return BCM_E_UNAVAIL;
   6875 }
   6876 
   6877 /*
   6878  * Function:
   6879  *     bcm_esw_l2_mac_port_traverse
   6880  * Description:
   6881  *     Traverse MAC ports.
   6882  * Parameters:
   6883  *     unit - (IN) BCM device number
   6884  *     cb   - (IN) Callback
   6885  *     user_data - (IN) User data
   6886  * Return:
   6887  *     BCM_E_XXX
   6888  */
   6889 int
   6890 bcm_esw_l2_mac_port_traverse(int unit, bcm_l2_mac_port_traverse_cb cb,
   6891         void *user_data)
   6892 {
   6893     return BCM_E_UNAVAIL;
   6894 }
   6895 
   6896 #ifndef BCM_SW_STATE_DUMP_DISABLE
   6897 
   6898 /*
   6899  * Function:
   6900  *     _bcm_l2_sw_dump
   6901  * Purpose:
   6902  *     Displays L2 information maintained by software.
   6903  * Parameters:
   6904  *     unit - Device unit number
   6905  * Returns:
   6906  *     None
   6907  * Note:
   6908  *    The l2_data structure maintains registration of callbacks routines.
   6909  *    Dump of l2_data is skipped.
   6910  */
   6911 void
   6912 _bcm_l2_sw_dump(int unit)
   6913 {
   6914 
   6915     LOG_CLI((BSL_META_U(unit,
   6916                         "\nSW Information L2 - Unit %d\n"), unit));
   6917     LOG_CLI((BSL_META_U(unit,
   6918                         "  Initialized : %d\n"), _l2_init[unit]));
   6919 
   6920 #if defined(BCM_TRX_SUPPORT)
   6921     if (SOC_IS_TRX(unit)) {
   6922         _bcm_tr_l2_sw_dump(unit); 
   6923     }
   6924 #endif
   6925 
   6926 #if defined(BCM_FIREBOLT_SUPPORT)
   6927     if (SOC_IS_FB_FX_HX(unit)) {
   6928         _bcm_fb_l2_sw_dump(unit);
   6929     }
   6930 #endif
   6931     return;
   6932 }
   6933 #endif /* BCM_SW_STATE_DUMP_DISABLE */
   6934 
   6935 STATIC void
   6936 _bcm_esw_l2_vlan_gport_free(int unit, _bcm_l2_del_vlan_port_pair_t *l2_pair)
   6937 {
   6938     int i;
   6939     
   6940     if (l2_pair) {
   6941         if (l2_pair->mod_pair_arr) {
   6942             sal_free(l2_pair->mod_pair_arr);
   6943             l2_pair->mod_pair_arr = NULL;
   6944         } 
   6945 
   6946         if (l2_pair->unit_pair_arr) {
   6947             for (i = 0; i < BCM_VLAN_MAX + 2; i++) {
   6948                 sal_free(l2_pair->unit_pair_arr->tbm[i]);
   6949                 l2_pair->unit_pair_arr->tbm[i] = NULL;
   6950             }
   6951             sal_free(l2_pair->unit_pair_arr);
   6952             l2_pair->unit_pair_arr = NULL;
   6953         }
   6954 
   6955         if (soc_feature(unit, soc_feature_vlan_vp)) {
   6956             if (l2_pair->vp_pair_arr) {
   6957                 for (i = 0; i < BCM_VLAN_MAX + 2; i++) {
   6958                     sal_free(l2_pair->vp_pair_arr->vpbm[i]);
   6959                     l2_pair->vp_pair_arr->vpbm[i] = NULL;
   6960                 }
   6961                 sal_free(l2_pair->vp_pair_arr);
   6962                 l2_pair->vp_pair_arr = NULL;
   6963             }
   6964         }
   6965 
   6966         if (l2_pair->vfi_pair_arr) {
   6967             for (i = 0; i < soc_mem_index_count(unit,VFIm); i++) {
   6968                 if (l2_pair->vfi_pair_arr[i]) {
   6969                     sal_free(l2_pair->vfi_pair_arr[i]);
   6970                     l2_pair->vfi_pair_arr[i] = NULL;
   6971                 }
   6972             }
   6973             sal_free(l2_pair->vfi_pair_arr);
   6974             l2_pair->vfi_pair_arr = NULL;
   6975         }
   6976 
   6977         if (l2_pair->del_by_vfi_vec) {
   6978             sal_free(l2_pair->del_by_vfi_vec);
   6979             l2_pair->del_by_vfi_vec = NULL;
   6980         }
   6981     }
   6982     return;
   6983 }
   6984 
   6985 #if defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3)
   6986 /*
   6987  * Function:
   6988  *     _bcm_is_gport_valid_vp_type
   6989  * Purpose:
   6990  *     Returns TRUE if supplied gport is a valid VP type
   6991  * Parameters:
   6992  *     gport_type    -  (IN) Gport type to be validated
   6993  * Returns:
   6994  *     TRUE if 'gport' is a valid VP type, FALSE otherwise
   6995  */
   6996 
   6997 int _bcm_is_gport_valid_vp_type(int gport_type)
   6998 {
   6999     switch(gport_type) {
   7000         case BCM_GPORT_MPLS_PORT:
   7001         case BCM_GPORT_SUBPORT_GROUP:
   7002         case BCM_GPORT_SUBPORT_PORT:
   7003         case BCM_GPORT_MIM_PORT:
   7004         case BCM_GPORT_VLAN_PORT:
   7005         case BCM_GPORT_TRILL_PORT:
   7006         case BCM_GPORT_NIV_PORT:
   7007         case BCM_GPORT_L2GRE_PORT:
   7008         case BCM_GPORT_VXLAN_PORT:
   7009         case BCM_GPORT_EXTENDER_PORT:
   7010             return 1;
   7011         default:
   7012             return 0;
   7013     }
   7014 }
   7015 
   7016 /*
   7017  * Function:
   7018  *     _bcm_is_gport_vp_in_use
   7019  * Purpose:
   7020  *     Returns TRUE if supplied gport-VP type is in use
   7021  * Parameters:
   7022  *     unit       -  (IN) Unit number
   7023  *     gport      -  (IN) Gport to check if in use
   7024  * Returns:
   7025  *     TRUE if 'gport-vp' is a valid and in use, FALSE otherwise.
   7026  */
   7027 int _bcm_is_gport_vp_in_use(int unit, int gport)
   7028 {
   7029     int vp;
   7030 
   7031     /* Extract the vp */
   7032     if (BCM_GPORT_IS_MPLS_PORT(gport)) {
   7033         vp = _SHR_GPORT_MPLS_PORT_ID_GET(gport);
   7034         return _bcm_vp_used_get(unit, vp, _bcmVpTypeMpls);
   7035     } else if (BCM_GPORT_IS_MIM_PORT(gport)) {
   7036         vp = _SHR_GPORT_MIM_PORT_ID_GET(gport);
   7037         return _bcm_vp_used_get(unit, vp, _bcmVpTypeMim);
   7038     } else if (BCM_GPORT_IS_L2GRE_PORT(gport)) {
   7039         vp = _SHR_GPORT_L2GRE_PORT_ID_GET(gport);
   7040         return _bcm_vp_used_get(unit, vp, _bcmVpTypeL2Gre);
   7041     } else if (BCM_GPORT_IS_SUBPORT_GROUP(gport)){
   7042         vp = _SHR_GPORT_SUBPORT_GROUP_GET(gport);
   7043         return _bcm_vp_used_get(unit, vp, _bcmVpTypeSubport);
   7044     } else if (BCM_GPORT_IS_WLAN_PORT(gport)) {
   7045         vp = _SHR_GPORT_WLAN_PORT_ID_GET(gport);
   7046         return _bcm_vp_used_get(unit, vp, _bcmVpTypeWlan);
   7047     } else if (BCM_GPORT_IS_VLAN_PORT(gport)) {
   7048         vp = _SHR_GPORT_VLAN_PORT_ID_GET(gport);
   7049         return _bcm_vp_used_get(unit, vp, _bcmVpTypeVlan);
   7050     } else if (BCM_GPORT_IS_TRILL_PORT(gport)) {
   7051         vp = _SHR_GPORT_TRILL_PORT_ID_GET(gport);
   7052         return _bcm_vp_used_get(unit, vp, _bcmVpTypeTrill);
   7053     } else if (BCM_GPORT_IS_NIV_PORT(gport)) {
   7054         vp = _SHR_GPORT_NIV_PORT_ID_GET(gport);
   7055         return _bcm_vp_used_get(unit, vp, _bcmVpTypeNiv);
   7056     } else if (BCM_GPORT_IS_EXTENDER_PORT(gport)) {
   7057         vp = _SHR_GPORT_EXTENDER_PORT_ID_GET(gport);
   7058         return _bcm_vp_used_get(unit, vp, _bcmVpTypeExtender);
   7059     } else if (BCM_GPORT_IS_VXLAN_PORT(gport)) {
   7060         vp = _SHR_GPORT_VXLAN_PORT_ID_GET(gport);
   7061         return _bcm_vp_used_get(unit, vp, _bcmVpTypeVxlan);
   7062     } else {
   7063         return 0;
   7064     }
   7065 }
   7066 
   7067 #endif /* defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3) */
   7068 
   7069 /*
   7070  * Function:
   7071  *     _bcm_esw_l2_vlan_gport_matched_delete
   7072  * Purpose:
   7073  *     L2 Traverse callback function to Purge L2 entry belongs
   7074  *     to set of (vlan,port) tuple.
   7075  * Parameters:
   7076  *     unit       -  (IN) Device unit number
   7077  *     info       -  (IN) Reference to L2 entry, delete on match
   7078  *     user_data  -  (IN) User specified cookie
   7079  * Returns:
   7080  *     BCM_E_XXX
   7081  * Note:
   7082  *     If one of the elements of the (vlan,gport) pair is invalid
   7083  *     (if vlan value is BCM_VLAN_INVALID or port value is BCM_GPORT_INVALID),
   7084  *     it is a wildcard. 
   7085  */
   7086 
   7087 
   7088 int
   7089 _bcm_esw_l2_vlan_gport_matched_delete(int unit, bcm_l2_addr_t *info, 
   7090                                       void *user_data)
   7091 {
   7092     int                            rv = BCM_E_NONE;
   7093     int                            entry_found=FALSE;
   7094     _bcm_l2_del_vlan_port_pair_t  *l2_pair;
   7095     int                            useGport;
   7096 #if defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3)
   7097     int                            gport_type;
   7098     bcm_port_t                     local_port;
   7099 #endif /* defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3) */
   7100     int vfi_num;
   7101 
   7102     l2_pair = (void *)user_data;
   7103 
   7104     if (l2_pair == NULL) {
   7105         return BCM_E_NOT_FOUND;
   7106     }
   7107 
   7108     if ((info->flags & BCM_L2_STATIC) &&  
   7109         (!(l2_pair->replace_flags & BCM_L2_REPLACE_MATCH_STATIC))) {
   7110         _l2_dbg_unmatched_entries[unit]++;  
   7111         return BCM_E_NONE;
   7112     }
   7113 
   7114     if ((info->flags & BCM_L2_PENDING) &&  
   7115         (!(l2_pair->replace_flags & BCM_L2_REPLACE_PENDING))) {
   7116         _l2_dbg_unmatched_entries[unit]++;
   7117         return BCM_E_NONE;
   7118     }
   7119 
   7120     BCM_IF_ERROR_RETURN
   7121         (bcm_esw_switch_control_get(unit, bcmSwitchUseGport, &useGport));
   7122 
   7123 #if defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3)
   7124     /* Extract the gport_type */
   7125     gport_type = (((info->port) >> _SHR_GPORT_TYPE_SHIFT) & _SHR_GPORT_TYPE_MASK);
   7126     if (_bcm_is_gport_valid_vp_type(gport_type)) {
   7127         BCM_IF_ERROR_RETURN(
   7128             bcm_esw_port_local_get(unit, info->port, &local_port));
   7129     }
   7130 #endif /* defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3) */
   7131     if (_BCM_VPN_VFI_IS_SET(info->vid)) {
   7132         _BCM_VPN_GET(vfi_num, _BCM_VPN_TYPE_VFI, info->vid);
   7133         if (l2_pair->del_by_vfi_vec &&
   7134                (SHR_BITGET(l2_pair->del_by_vfi_vec, vfi_num))) {
   7135             entry_found = TRUE;
   7136         }
   7137 #if defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3)
   7138         else if (_bcm_is_gport_valid_vp_type(gport_type)) {
   7139             if (l2_pair->vfi_pair_arr &&
   7140                     (vfi_num < soc_mem_index_count(unit,VFIm)) &&
   7141                     l2_pair->vfi_pair_arr[vfi_num]) {
   7142                 if (SHR_BITGET(l2_pair->vfi_pair_arr[vfi_num], local_port)) {
   7143                     entry_found = TRUE;
   7144                 }
   7145             }
   7146         }
   7147 #endif /* defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3) */
   7148 
   7149     } else if (BCM_VLAN_VEC_GET(l2_pair->del_by_vlan_vec, info->vid)) {
   7150         /* Delete by vlan operation */
   7151         entry_found = TRUE;
   7152     } else if ((useGport) && (BCM_GPORT_IS_MODPORT(info->port)) &&
   7153                BCM_PBMP_MEMBER (l2_pair->mod_pair_arr[info->modid].pbm[BCM_VLAN_MAX+1],
   7154                                 _SHR_GPORT_LOCAL_GET(info->port))) {
   7155         /* Delete by (mod, gport) operation */
   7156         entry_found = TRUE;
   7157     } else if ((!useGport) && (!BCM_GPORT_IS_SET(info->port)) &&
   7158                BCM_PBMP_MEMBER (l2_pair->mod_pair_arr[info->modid].pbm[BCM_VLAN_MAX+1],
   7159                                 info->port)) {
   7160         /* Delete by (mod, port) operation */
   7161         entry_found = TRUE;
   7162     } else if ((useGport) && BCM_GPORT_IS_MODPORT(info->port) &&
   7163                BCM_PBMP_MEMBER(l2_pair->mod_pair_arr[info->modid].pbm[info->vid],
   7164                 _SHR_GPORT_LOCAL_GET(info->port))) {
   7165         /* Delete by (vlan, (mod, gport)) operation */
   7166         entry_found = TRUE;
   7167     } else if (((!useGport) && (!BCM_GPORT_IS_SET(info->port)) &&
   7168                 BCM_PBMP_MEMBER(l2_pair->mod_pair_arr[info->modid].pbm[info->vid],
   7169                 info->port))) {
   7170         /* Delete by (vlan, (mod, port)) operation */
   7171         entry_found = TRUE;
   7172     } else if (info->flags & BCM_L2_TRUNK_MEMBER) {
   7173         if (SHR_BITGET(l2_pair->unit_pair_arr[0].tbm[BCM_VLAN_MAX+1], info->tgid)) {
   7174             /* Delete by (tid) operation */
   7175             entry_found = TRUE;
   7176         } else if (SHR_BITGET(l2_pair->unit_pair_arr[0].tbm[info->vid], info->tgid)) {
   7177             /* Delete by (vlan, tid) operation */
   7178             entry_found = TRUE;
   7179         }
   7180     } else { 
   7181 
   7182 #if defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3)
   7183         if (_bcm_is_gport_valid_vp_type(gport_type)) {
   7184             if (SHR_BITGET(l2_pair->vp_pair_arr[0].vpbm[BCM_VLAN_MAX+1],
   7185                            local_port)) {
   7186                 /* Delete by (vp) operation */
   7187                 entry_found = TRUE;
   7188             } else if (SHR_BITGET(l2_pair->vp_pair_arr[0].vpbm[info->vid], 
   7189                                   local_port)) {
   7190                 /* Delete by (vlan, vp) operation */
   7191                 entry_found = TRUE;
   7192             }
   7193         }
   7194 #endif /* defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3) */
   7195     }
   7196 
   7197     if (entry_found == TRUE) {
   7198        /* Entry found - Delete the entry */
   7199 #if defined(BCM_TRIUMPH3_SUPPORT)
   7200        if (soc_feature(unit, soc_feature_ism_memory)) {
   7201            rv = bcm_tr3_l2_addr_delete(unit, info->mac, info->vid);
   7202        } else
   7203 #endif /* BCM_TRIUMPH3_SUPPORT */    
   7204        rv = mbcm_driver[unit]->mbcm_l2_addr_delete(unit, info->mac,
   7205                                                    info->vid);
   7206        if (rv == BCM_E_NONE) {
   7207            _l2_dbg_matched_entries[unit]++;
   7208        }
   7209    } else {
   7210        _l2_dbg_unmatched_entries[unit]++;
   7211    }
   7212 
   7213    return rv;
   7214 }
   7215 
   7216 /*
   7217  * Function:
   7218  *     bcm_esw_l2_addr_delete_by_vlan_gport_multi
   7219  * Purpose:
   7220  *     Purge L2 entries belong to set of (vlan,port) tuple.
   7221  * Parameters:
   7222  *     unit       -  (IN) Device unit number
   7223  *     flags      -  (IN) Only accept BCM_L2_REPLACE_DELETE, BCM_L2_REPLACE_NO_CALLBACKS.
   7224  *     num_pairs  -  (IN) Size of (vlan,port) pair array.
   7225  *     vlan       -  (IN) Reference to array of VLAN list.
   7226  *     gport      -  (IN) Reference to array of gport list.
   7227  * Returns:
   7228  *     BCM_E_XXX
   7229  * Note:
   7230  *     If one of the elements of the (vlan,gport) pair is invalid
   7231  *     (if vlan value is BCM_VLAN_INVALID or port value is BCM_GPORT_INVALID),
   7232  *     it is a wildcard.
   7233  *     Entries are removed only if BCM_L2_REPLACE_DELETE flag is used. With
   7234  *     flag BCM_L2_REPLACE_NO_CALLBACKS, l2 aging and learning are disabled 
   7235  *     during this operation.
   7236  */
   7237 
   7238 int 
   7239 bcm_esw_l2_addr_delete_by_vlan_gport_multi(int unit, uint32 flags, 
   7240                                            int num_pairs, bcm_vlan_t *vlan,
   7241                                            bcm_gport_t *gport)
   7242 {
   7243     sal_usecs_t                   interval=0;
   7244     bcm_module_t                  mod_in, modid = 0;
   7245     bcm_port_t                    port_in, port = 0;
   7246     bcm_trunk_t                   trunk_id = 0;
   7247     int                           id = 0, ct, i;
   7248     int                           rv2 = 0, rv = BCM_E_UNAVAIL;
   7249     soc_control_t                 *soc = SOC_CONTROL(unit);
   7250     uint32                        max_modid;
   7251     _bcm_l2_vlan_port_pair_t      *mod_l2_pair_arr = NULL;
   7252     _bcm_l2_vlan_trunk_pair_t     *l2_trunk_pair_arr = NULL;
   7253     _bcm_l2_vlan_vp_pair_t        *l2_vp_pair_arr = NULL;
   7254     _bcm_l2_del_vlan_port_pair_t  l2_pair;
   7255     int                           alloc_size;
   7256     int                           fifo_modified = FALSE;
   7257     int                           vfi_num; 
   7258     int                           vfi_max;
   7259     uint32                        rval = 0;
   7260     uint32                        l2_delete = 0;
   7261 
   7262 #if defined(BCM_TOMAHAWK3_SUPPORT)
   7263     /* Added to handle SDK functions calling esw version,
   7264      * instead of Tomahawk3's version
   7265      */
   7266     if (SOC_IS_TOMAHAWK3(unit)) {
   7267         return bcm_tomahawk3_l2_addr_delete_by_vlan_gport_multi(unit, flags,
   7268                                                                 num_pairs, vlan,
   7269                                                                 gport);
   7270     }
   7271 #endif /* BCM_TOMAHAWK3_SUPPORT  */
   7272 
   7273     /* Validate the input parameters */
   7274     if (vlan == NULL || gport == NULL || num_pairs == 0) {
   7275         return BCM_E_PARAM;
   7276     }
   7277 
   7278     /* Validate flag parameter, no action will be proceeded with extra flags */
   7279     if ((flags & ~(BCM_L2_REPLACE_DELETE | BCM_L2_REPLACE_NO_CALLBACKS | 
   7280                    BCM_L2_REPLACE_MATCH_STATIC |
   7281                    BCM_L2_REPLACE_PENDING )) != 0) {
   7282         return BCM_E_NONE;
   7283     }
   7284 
   7285     if (SOC_MEM_IS_VALID(unit, VFIm)) {
   7286         vfi_max = soc_mem_index_count(unit,VFIm);
   7287     } else {
   7288         vfi_max = 0;
   7289     }
   7290     sal_memset(&l2_pair, 0x0, sizeof(l2_pair));
   7291     
   7292     /* Prepare (vlan, (mod, port)) pair */
   7293     max_modid = SOC_MODID_MAX(unit) + 1;  
   7294     alloc_size = sizeof(_bcm_l2_vlan_port_pair_t) * max_modid;
   7295     mod_l2_pair_arr = sal_alloc(alloc_size, "l2_addr_vlan_gport_multi_delete");
   7296     if (mod_l2_pair_arr == NULL) {
   7297         return BCM_E_MEMORY;
   7298     }
   7299     sal_memset(mod_l2_pair_arr, 0x0, alloc_size);
   7300 
   7301     /* Prepare (vlan, tid) pair */
   7302     l2_pair.mod_pair_arr = mod_l2_pair_arr;
   7303     alloc_size = sizeof(_bcm_l2_vlan_trunk_pair_t);
   7304     l2_trunk_pair_arr = sal_alloc(alloc_size, "l2_addr_vlan_gport_multi_delete");
   7305     if (l2_trunk_pair_arr == NULL) {
   7306         rv = BCM_E_MEMORY;
   7307         goto _free_exit;
   7308     }
   7309     sal_memset(l2_trunk_pair_arr, 0x0, alloc_size);
   7310     l2_pair.unit_pair_arr = l2_trunk_pair_arr;
   7311     
   7312     alloc_size = SHR_BITALLOCSIZE(_bcm_esw_trunk_group_num(unit));
   7313     for (i = 0; i < BCM_VLAN_MAX + 2; i++) {
   7314         l2_trunk_pair_arr->tbm[i] = sal_alloc(alloc_size, \
   7315             "l2_addr_vlan_gport_multi_delete");
   7316         if (l2_trunk_pair_arr->tbm[i] == NULL) {
   7317             rv = BCM_E_MEMORY;
   7318             goto _free_exit;
   7319         }
   7320         sal_memset(l2_trunk_pair_arr->tbm[i], 0x0, alloc_size);
   7321     }
   7322 
   7323     if (soc_feature(unit, soc_feature_vlan_vp)) {
   7324         /* Prepare (vlan, vp) pair */
   7325         alloc_size = sizeof(_bcm_l2_vlan_vp_pair_t);
   7326         l2_vp_pair_arr = sal_alloc(alloc_size, "l2_addr_vlan_gport_multi_delete");
   7327         if (l2_vp_pair_arr == NULL) {
   7328             rv = BCM_E_MEMORY;
   7329             goto _free_exit;
   7330         }
   7331         sal_memset(l2_vp_pair_arr, 0x0, alloc_size);
   7332         l2_pair.vp_pair_arr = l2_vp_pair_arr;
   7333 
   7334         alloc_size = SHR_BITALLOCSIZE(soc_mem_index_count(unit, SOURCE_VPm));
   7335         for (i = 0; i < BCM_VLAN_MAX + 2; i++) {
   7336             l2_vp_pair_arr->vpbm[i] = sal_alloc(alloc_size, \
   7337                 "l2_addr_vlan_gport_multi_delete");
   7338             if (l2_vp_pair_arr->vpbm[i] == NULL) {
   7339                 rv = BCM_E_MEMORY;
   7340                 goto _free_exit;
   7341             }
   7342             sal_memset(l2_vp_pair_arr->vpbm[i], 0x0, alloc_size);
   7343         }
   7344     }
   7345 
   7346     if (SOC_MEM_IS_VALID(unit, VFIm) &&
   7347         SOC_MEM_IS_VALID(unit,SOURCE_VPm)) {
   7348          alloc_size = sizeof(SHR_BITDCL *) *  vfi_max;
   7349          l2_pair.vfi_pair_arr = sal_alloc(alloc_size, 
   7350                        "l2_addr_vlan_gport_multi_delete:vfi_pair_arr");
   7351          if (l2_pair.vfi_pair_arr == NULL) {
   7352              rv = BCM_E_MEMORY;
   7353              goto _free_exit;
   7354          }
   7355          
   7356          sal_memset(l2_pair.vfi_pair_arr, 0x0, alloc_size);
   7357 
   7358          alloc_size = SHR_BITALLOCSIZE(vfi_max); 
   7359          l2_pair.del_by_vfi_vec = sal_alloc(alloc_size, 
   7360                         "l2_addr_vlan_gport_multi_delete:del_by_vfi_vec");
   7361          if (l2_pair.del_by_vfi_vec == NULL) {
   7362              rv = BCM_E_MEMORY;
   7363              goto _free_exit;
   7364          }
   7365          sal_memset(l2_pair.del_by_vfi_vec, 0x0, alloc_size);
   7366          
   7367     }
   7368          
   7369     /* Validate vlan & gport */
   7370     for (ct = 0; ct < num_pairs; ct++) {
   7371         if (vlan[ct] == BCM_VLAN_INVALID && 
   7372             gport[ct] == BCM_GPORT_INVALID) {
   7373             rv = BCM_E_PARAM;
   7374             goto _free_exit;
   7375         }
   7376 
   7377         if (vlan[ct] != BCM_VLAN_INVALID) {
   7378             if ((vlan[ct] > BCM_VLAN_MAX) && 
   7379                 (!_BCM_VPN_VFI_IS_SET(vlan[ct]))) {
   7380                 rv = BCM_E_PARAM;
   7381                 goto _free_exit;
   7382             }
   7383         }
   7384 
   7385         if (_BCM_VPN_VFI_IS_SET(vlan[ct])) {
   7386             if (gport[ct] != BCM_GPORT_INVALID) {
   7387 #if defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3)
   7388                 if(!(_bcm_is_gport_vp_in_use(unit, gport[ct]))) {
   7389                     rv = BCM_E_PARAM;
   7390                     goto _free_exit;
   7391                 }
   7392 #endif /* defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3) */
   7393             }
   7394         }
   7395         if (gport[ct] != BCM_GPORT_INVALID) { 
   7396 
   7397             if (BCM_GPORT_IS_MODPORT(gport[ct])) {
   7398                 mod_in = BCM_GPORT_MODPORT_MODID_GET(gport[ct]);
   7399                 port_in = BCM_GPORT_MODPORT_PORT_GET(gport[ct]);
   7400                 rv = _bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET,
   7401                                            mod_in, port_in, &modid, &port);
   7402                 if (BCM_FAILURE(rv)) {
   7403                     goto _free_exit;
   7404                 }
   7405             } else {            
   7406                 rv = _bcm_esw_gport_resolve(unit, gport[ct],
   7407                                        &modid, &port, &trunk_id, &id);
   7408                 if (BCM_FAILURE(rv)) {
   7409                     goto _free_exit;
   7410                 }
   7411             
   7412                 if (BCM_GPORT_IS_TRUNK(gport[ct])) {
   7413                     rv = _bcm_trunk_id_validate(unit, trunk_id);
   7414                     if (BCM_FAILURE(rv)) {
   7415                         rv = BCM_E_PARAM;
   7416                         goto _free_exit;
   7417                     }
   7418                 } else {
   7419                     /* If the VP type is not in use, return error */
   7420 #if defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3)
   7421                     if(!(_bcm_is_gport_vp_in_use(unit, gport[ct]))) {
   7422                         rv = BCM_E_PARAM;
   7423                         goto _free_exit;
   7424                     }
   7425 #else
   7426                     rv = BCM_E_PARAM;
   7427                     goto _free_exit;
   7428 #endif /* defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3) */
   7429                 }
   7430             }
   7431         }
   7432 
   7433         if (vlan[ct] == BCM_VLAN_INVALID) {
   7434             if (BCM_GPORT_IS_TRUNK(gport[ct])) {
   7435                 SHR_BITSET(l2_pair.unit_pair_arr[0].tbm[BCM_VLAN_MAX+1], \
   7436                     trunk_id);
   7437             } else if (BCM_GPORT_IS_MODPORT(gport[ct])){
   7438                 BCM_PBMP_PORT_ADD( \
   7439                     l2_pair.mod_pair_arr[modid].pbm[BCM_VLAN_MAX+1], port);
   7440             } else {
   7441                 if (soc_feature(unit, soc_feature_vlan_vp)) {
   7442                     /* VP case, set relevant bit */
   7443                     SHR_BITSET(l2_pair.vp_pair_arr[0].vpbm[BCM_VLAN_MAX+1], \
   7444                         id);
   7445                 }
   7446             }
   7447         } else if (gport[ct] == BCM_GPORT_INVALID) {
   7448             if (_BCM_VPN_VFI_IS_SET(vlan[ct])) {
   7449                 _BCM_VPN_GET(vfi_num, _BCM_VPN_TYPE_VFI, vlan[ct]);
   7450                 if (l2_pair.del_by_vfi_vec == NULL ||
   7451                     vfi_num >= vfi_max) {
   7452                     rv = BCM_E_PARAM;
   7453                     goto _free_exit;
   7454                 }
   7455                 SHR_BITSET(l2_pair.del_by_vfi_vec,vfi_num); 
   7456             } else {
   7457                 BCM_VLAN_VEC_SET(l2_pair.del_by_vlan_vec, vlan[ct]);
   7458             }
   7459         } else {
   7460             if (BCM_GPORT_IS_TRUNK(gport[ct])) {
   7461                 SHR_BITSET(l2_pair.unit_pair_arr[0].tbm[vlan[ct]], \
   7462                     trunk_id);                
   7463             } else if (BCM_GPORT_IS_MODPORT(gport[ct])){
   7464                 BCM_PBMP_PORT_ADD(l2_pair.mod_pair_arr[modid].pbm[vlan[ct]], \
   7465                     port);
   7466             } else {
   7467                 if (_BCM_VPN_VFI_IS_SET(vlan[ct])) {
   7468                     _BCM_VPN_GET(vfi_num, _BCM_VPN_TYPE_VFI, vlan[ct]);
   7469                     if (l2_pair.vfi_pair_arr == NULL ||
   7470                         vfi_num >= vfi_max) {
   7471                         rv = BCM_E_PARAM;
   7472                         goto _free_exit;
   7473                     }
   7474                     if (l2_pair.vfi_pair_arr[vfi_num] == NULL) {
   7475                         alloc_size = SHR_BITALLOCSIZE(soc_mem_index_count(unit,SOURCE_VPm));
   7476                         l2_pair.vfi_pair_arr[vfi_num] = sal_alloc(alloc_size,
   7477                                      "l2_addr_vlan_gport_multi_delete");
   7478                         if (l2_pair.vfi_pair_arr[vfi_num] == NULL) {
   7479                             rv = BCM_E_MEMORY;
   7480                             goto _free_exit;
   7481                         }
   7482                         sal_memset(l2_pair.vfi_pair_arr[vfi_num], 0x0, alloc_size);
   7483                     }    
   7484                     SHR_BITSET(l2_pair.vfi_pair_arr[vfi_num], id);
   7485 
   7486                 } else if (soc_feature(unit, soc_feature_vlan_vp)) {
   7487                     /* Vlan VP case, set relevant bit */
   7488                     SHR_BITSET(l2_pair.vp_pair_arr[0].vpbm[vlan[ct]], \
   7489                         id);
   7490                 }
   7491             }
   7492         }
   7493     }
   7494 
   7495     if (flags & BCM_L2_REPLACE_DELETE) {
   7496         _l2_dbg_matched_entries[unit] = 0;
   7497         _l2_dbg_unmatched_entries[unit] = 0;
   7498 
   7499         if (flags & BCM_L2_REPLACE_NO_CALLBACKS) {
   7500             interval = soc->l2x_interval;
   7501             rv = bcm_esw_l2_addr_freeze(unit);
   7502             if (BCM_FAILURE(rv)) {
   7503                 goto _free_exit;
   7504             }
   7505 
   7506             if (SOC_CONTROL(unit)->l2x_mode == L2MODE_FIFO &&
   7507                 soc_l2mod_running(unit, NULL, NULL)) {
   7508                 if (SOC_REG_IS_VALID(unit, L2_MOD_FIFO_ENABLEr)) {
   7509                     rv2 = READ_L2_MOD_FIFO_ENABLEr(unit, &rval);
   7510                     if (rv2 < 0) {
   7511                         goto _free_exit;
   7512                     }
   7513                     l2_delete = soc_reg_field_get(unit, L2_MOD_FIFO_ENABLEr, rval,
   7514                                                   L2_DELETEf);
   7515                     rv2 = soc_reg_field32_modify(unit, L2_MOD_FIFO_ENABLEr,
   7516                             REG_PORT_ANY, L2_DELETEf, 0);
   7517                 } else {
   7518                     if (soc_reg_field_valid(unit, AUX_ARB_CONTROLr,
   7519                                         L2_MOD_FIFO_ENABLE_L2_DELETEf)) {
   7520                         rv2 = READ_AUX_ARB_CONTROLr(unit, &rval);
   7521                         if (rv2 < 0) {
   7522                             goto _free_exit;
   7523                         }
   7524                         l2_delete = soc_reg_field_get(unit, AUX_ARB_CONTROLr, rval,
   7525                                                       L2_MOD_FIFO_ENABLE_L2_DELETEf);
   7526                         rv2 = soc_reg_field32_modify(unit, AUX_ARB_CONTROLr,
   7527                                 REG_PORT_ANY, L2_MOD_FIFO_ENABLE_L2_DELETEf, 0);
   7528                     }
   7529                 }
   7530 
   7531                 if (rv2 < 0) {
   7532                     goto _free_exit;
   7533                 }
   7534                 fifo_modified = TRUE;
   7535             } else if (SOC_CONTROL(unit)->l2x_mode != L2MODE_FIFO) {
   7536                 rv2 = soc_l2x_stop(unit);
   7537                 if (rv2 < 0) {
   7538                     goto _free_exit;
   7539                 }
   7540             }
   7541 
   7542             LOG_INFO(BSL_LS_BCM_ARL,
   7543                      (BSL_META_U(unit, "L2 Freeze and stop L2 thread\n")));
   7544         }
   7545 
   7546         l2_pair.replace_flags   = flags;
   7547         rv = bcm_esw_l2_traverse(unit, _bcm_esw_l2_vlan_gport_matched_delete,
   7548                                  &l2_pair);
   7549         if (rv == BCM_E_NONE) {
   7550             LOG_INFO(BSL_LS_BCM_ARL,
   7551                      (BSL_META_U(unit,
   7552                                  "Total number of L2 Entries: %d [Deleted:%d Left:%d]\n\r"),
   7553                       _l2_dbg_matched_entries[unit] + _l2_dbg_unmatched_entries[unit],
   7554                       _l2_dbg_matched_entries[unit], _l2_dbg_unmatched_entries[unit]));
   7555         }
   7556 
   7557         if (flags & BCM_L2_REPLACE_NO_CALLBACKS) {
   7558             LOG_INFO(BSL_LS_BCM_ARL,
   7559                      (BSL_META_U(unit, "L2 Thaw and start L2 thread\n")));
   7560 
   7561             if (fifo_modified) {
   7562                 if (SOC_REG_IS_VALID(unit, L2_MOD_FIFO_ENABLEr)) {
   7563                     rv2 = soc_reg_field32_modify(unit, L2_MOD_FIFO_ENABLEr,
   7564                             REG_PORT_ANY, L2_DELETEf, l2_delete);
   7565                 } else {
   7566                     if (soc_reg_field_valid(unit, AUX_ARB_CONTROLr,
   7567                                         L2_MOD_FIFO_ENABLE_L2_DELETEf)) {
   7568                         rv2 = soc_reg_field32_modify(unit, AUX_ARB_CONTROLr,
   7569                                 REG_PORT_ANY, L2_MOD_FIFO_ENABLE_L2_DELETEf, l2_delete);
   7570                     }
   7571                 }
   7572 
   7573                 if (rv2 < 0) {
   7574                     goto _free_exit;
   7575                 }
   7576             } else if (SOC_CONTROL(unit)->l2x_mode != L2MODE_FIFO) {
   7577                 rv2 = soc_l2x_start(unit, soc->l2x_flags, interval);
   7578                 if (rv2 < 0) {
   7579                     goto _free_exit;
   7580                 }
   7581             }
   7582 
   7583             rv2 = bcm_esw_l2_addr_thaw(unit);
   7584             if (rv2 < 0) {
   7585                 goto _free_exit;
   7586             }
   7587         }
   7588     }
   7589 
   7590 _free_exit:
   7591     _bcm_esw_l2_vlan_gport_free(unit, &l2_pair);
   7592 
   7593     if (rv < 0) {
   7594         return rv;
   7595     } else if (rv2 < 0) {
   7596         return rv2;
   7597     } else {
   7598         return rv;
   7599     }
   7600 }
   7601 
   7602 #if defined(INCLUDE_L3)
   7603 /*
   7604  * Function:
   7605  *  bcm_esw_l2_change_fields_add
   7606  * Description:
   7607  *	Add a Change L2 fields entry to the egress xlate table.
   7608  * Parameters:
   7609  *	unit - (IN) Device number.
   7610  *  l2_change_fields - (IN)
   7611  *      IN: l2 header info: rewrite L2 fields
   7612  * Returns:
   7613  *	BCM_E_XXX
   7614  */
   7615 int
   7616 bcm_esw_l2_change_fields_add(
   7617     int unit,
   7618     bcm_l2_change_fields_t *l2_info)
   7619 {
   7620 #if defined(BCM_TRIDENT3_SUPPORT)
   7621     if (soc_feature(unit, soc_feature_vfi_switched_l2_change_fields)) {
   7622         /* validate input */
   7623         if (NULL == l2_info) {
   7624             return BCM_E_PARAM;
   7625         }
   7626 
   7627         /* validate opaque object id */
   7628         if (l2_info->change_l2_fields_class_id > 0xffff) {
   7629             return BCM_E_PARAM;
   7630         }
   7631 
   7632         VLAN_CHK_ID(unit, l2_info->vlan);
   7633 
   7634         return _bcm_td3_l2_change_fields_add(unit, l2_info);
   7635     }
   7636 #endif /* BCM_TRIDENT3_SUPPORT */
   7637 
   7638     return BCM_E_UNAVAIL;
   7639 }
   7640 
   7641 /* Function:
   7642  *  bcm_esw_l2_change_fields_delete
   7643  * Description:
   7644  *  Delete the l2 change fields from EVXLT table.
   7645  * Parameters:
   7646  *  unit     - (IN) Device number.
   7647  *  l2_info  - (IN) key fields to be deleted.
   7648  */
   7649 int
   7650 bcm_esw_l2_change_fields_delete(
   7651     int unit,
   7652     bcm_l2_change_fields_t *l2_info)
   7653 {
   7654 #if defined(BCM_TRIDENT3_SUPPORT)
   7655     soc_mem_t mem = EGR_VLAN_XLATE_2_DOUBLEm;
   7656     soc_field_t tag_act_f = CHANGE_L2_FIELDS__TAG_ACTION_PROFILE_PTRf;
   7657     soc_field_t tpid_f = CHANGE_L2_FIELDS__TPID_INDEXf;
   7658     uint32 entry[SOC_MAX_MEM_WORDS];
   7659     uint32 return_entry[SOC_MAX_MEM_WORDS];
   7660     uint32 profile_index = 0;
   7661     uint32 tpid_inx = 0;
   7662     int index = 0;
   7663     int action_present=0, action_not_present=0;
   7664 
   7665     if (soc_feature(unit, soc_feature_vfi_switched_l2_change_fields)) {
   7666         /* validate input */
   7667         if (NULL == l2_info) {
   7668             return BCM_E_PARAM;
   7669         }
   7670 
   7671         /* validate opaque object id */
   7672         if (l2_info->change_l2_fields_class_id > 0xffff) {
   7673             return BCM_E_PARAM;
   7674         }
   7675 
   7676         sal_memset(entry, 0, sizeof(entry));
   7677 
   7678         BCM_IF_ERROR_RETURN(
   7679             _bcm_td3_l2_change_fields_egress_key_set(unit,
   7680                  mem, l2_info, entry));
   7681 
   7682         /* first free any tag action profile entry */
   7683         BCM_IF_ERROR_RETURN(
   7684             soc_mem_search(unit, mem, MEM_BLOCK_ANY, &index,
   7685              entry, return_entry, 0));
   7686 
   7687         profile_index = soc_mem_field32_get(unit, mem,
   7688             return_entry, tag_act_f);
   7689 
   7690         BCM_IF_ERROR_RETURN(_bcm_td3_sd_tag_action_get(unit,
   7691             profile_index, &action_present, &action_not_present));
   7692 
   7693         if (profile_index != 0) {
   7694             BCM_IF_ERROR_RETURN(
   7695                 _bcm_trx_egr_vlan_action_profile_entry_delete(unit,
   7696                  profile_index));
   7697         }
   7698 
   7699         if ((action_not_present == 0x1) || (action_present == 0x1) ||
   7700             (action_present == 0x4) || (action_present == 0x7)) {
   7701             tpid_inx = soc_mem_field32_get(unit, mem,
   7702                 return_entry, tpid_f);
   7703 
   7704             BCM_IF_ERROR_RETURN(_bcm_fb2_outer_tpid_entry_delete(unit,
   7705                 tpid_inx));
   7706         }
   7707 
   7708         /* now delete entry */
   7709         BCM_IF_ERROR_RETURN(soc_mem_delete(unit,
   7710                  mem, MEM_BLOCK_ANY, entry));
   7711 
   7712         return BCM_E_NONE;
   7713     }
   7714 #endif /* BCM_TRIDENT3_SUPPORT */
   7715 
   7716     return BCM_E_UNAVAIL;
   7717 }
   7718 
   7719 /* Function:
   7720  *  bcm_esw_l2_change_fields_get
   7721  * Description:
   7722  *  Retrieve the change l2 entry given the key fields
   7723  * Parameters:
   7724  *  unit    - (IN) Device number.
   7725  *  nat_id  - IN Index of entry to get.
   7726  */
   7727 int
   7728 bcm_esw_l2_change_fields_get(
   7729     int unit,
   7730     bcm_l2_change_fields_t *l2_info)
   7731 {
   7732 #if defined(BCM_TRIDENT3_SUPPORT)
   7733     soc_mem_t mem = EGR_VLAN_XLATE_2_DOUBLEm;
   7734     uint32 entry[SOC_MAX_MEM_WORDS];
   7735 
   7736     if (soc_feature(unit, soc_feature_vfi_switched_l2_change_fields)) {
   7737         /* validate input */
   7738         if (NULL == l2_info) {
   7739             return BCM_E_PARAM;
   7740         }
   7741 
   7742         /* validate opaque object id */
   7743         if (l2_info->change_l2_fields_class_id > 0xffff) {
   7744             return BCM_E_PARAM;
   7745         }
   7746 
   7747         sal_memset(entry, 0, sizeof(entry));
   7748 
   7749         BCM_IF_ERROR_RETURN(
   7750             _bcm_td3_l2_change_fields_egress_key_set(unit,
   7751                  mem, l2_info, entry));
   7752 
   7753         return _bcm_td3_l2_change_fields_egress_entry_get(unit,
   7754                     mem, entry, l2_info);
   7755     }
   7756 #endif /* BCM_TRIDENT3_SUPPORT */
   7757     return BCM_E_UNAVAIL;
   7758 }
   7759 
   7760 /* Function:
   7761  *  bcm_esw_l2_change_fields_traverse
   7762  *
   7763  * Description:
   7764  *  Traverse all valid change L2 entries in the egress translate table
   7765  *  and call the supplied callback routine for each.
   7766  *
   7767  * Parameters:
   7768  *  unit    - (IN) Device number.
   7769  *  cb      - (IN) User call-back function
   7770  */
   7771 int
   7772 bcm_esw_l2_change_fields_traverse(
   7773     int unit,
   7774     bcm_l2_change_fields_traverse_cb cb,
   7775     void *user_data)
   7776 {
   7777 #if defined(BCM_TRIDENT3_SUPPORT)
   7778     if (soc_feature(unit, soc_feature_vfi_switched_l2_change_fields)) {
   7779         if (NULL == cb) {
   7780             return BCM_E_NONE;
   7781         }
   7782 
   7783         return _bcm_td3_change_l2_fields_entry_traverse(unit,
   7784                     EGR_VLAN_XLATE_2_DOUBLEm, cb, user_data);
   7785     }
   7786 
   7787 #endif /* BCM_TRIDENT3_SUPPORT */
   7788     return BCM_E_UNAVAIL;
   7789 }
   7790 #endif /* INCLUDE_L3 */
   7791 
   7792 #ifdef BCM_WARM_BOOT_SUPPORT
   7793 
   7794 #define BCM_WB_VERSION_1_0                SOC_SCACHE_VERSION(1,0)
   7795 #define BCM_WB_VERSION_1_1                SOC_SCACHE_VERSION(1,1)
   7796 #define BCM_WB_DEFAULT_VERSION            BCM_WB_VERSION_1_1
   7797 
   7798 /*
   7799  * Function:
   7800  *      _bcm_esw_l2_wb_alloc
   7801  * Purpose:
   7802  *      Allocated L2 module persistent info for Level 2 Warm Boot
   7803  * Parameters:
   7804  *      unit - StrataSwitch unit number.
   7805  * Returns:
   7806  *      BCM_E_XXX
   7807  */
   7808 STATIC int
   7809 _bcm_esw_l2_wb_alloc(int unit)
   7810 {
   7811 #if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT)
   7812     int                         sz = 0;
   7813     soc_scache_handle_t         scache_handle;
   7814     uint8                       *scache_ptr;
   7815     int                         rv = BCM_E_NONE;
   7816     int                         stable_size = 0;
   7817     _bcm_l2_station_control_t   *station_control = NULL;
   7818     int                         sw_aging_support; /* SW Learning supported */
   7819     int                         underlay_max_entries = 0;
   7820 #ifdef BCM_RIOT_SUPPORT
   7821     int                         overlay_max_entries = 0;
   7822 #endif /* BCM_RIOT_SUPPORT */
   7823 
   7824     SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size));
   7825     /* Requires extended scache support warmboot */
   7826     if (stable_size == 0) {
   7827         return BCM_E_NONE;
   7828     }
   7829 
   7830     rv = _bcm_l2_station_control_get(unit, &station_control);
   7831     if (BCM_FAILURE(rv) && (rv != BCM_E_INIT)) {
   7832         return rv;
   7833     }
   7834 
   7835     sw_aging_support = SOC_IS_TRIUMPH3(unit);
   7836 #ifdef BCM_TOMAHAWK_SUPPORT
   7837     /* TH/TD3 does not support SW aging. Added only for warmboot upgrade purpose. */
   7838     sw_aging_support = sw_aging_support || SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit);
   7839 #endif /* BCM_TOMAHAWK_SUPPORT */
   7840 #ifdef BCM_TRIDENT2_SUPPORT
   7841     sw_aging_support = sw_aging_support || SOC_CONTROL(unit)->l2x_sw_aging;
   7842 #endif /* BCM_TRIDENT2_SUPPORT */
   7843 
   7844     if (sw_aging_support ||
   7845         ((!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) && station_control)) {
   7846 
   7847         SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_L2, 0);
   7848 
   7849         if (sw_aging_support) {
   7850             /* aging time */
   7851             sz += sizeof(int);
   7852         }
   7853 
   7854         if ((!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) && station_control) {
   7855             /* Underlay L2 station entry - sid/prio */
   7856             BCM_IF_ERROR_RETURN(
   7857                 _bcm_tr_l2_station_entry_max_size_get(unit, FALSE,
   7858                                                       &underlay_max_entries));
   7859             sz += (underlay_max_entries * (sizeof(int) * 2));
   7860 
   7861 #ifdef BCM_RIOT_SUPPORT
   7862             /* Overlay L2 station entry - sid/prio */
   7863             BCM_IF_ERROR_RETURN(
   7864                 _bcm_tr_l2_station_entry_max_size_get(unit, TRUE,
   7865                                                       &overlay_max_entries));
   7866 
   7867             sz += (overlay_max_entries * (sizeof(int) * 2));
   7868 #endif /* BCM_RIOT_SUPPORT */
   7869 
   7870         }
   7871 
   7872         rv = _bcm_esw_scache_ptr_get(unit, scache_handle, TRUE,
   7873                                      sz, &scache_ptr,
   7874                                      BCM_WB_DEFAULT_VERSION, NULL);
   7875 
   7876         if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) {
   7877             return rv;
   7878         }
   7879     }
   7880 #endif /* BCM_TRIDENT_SUPPORT || BCM_GREYHOUND2_SUPPORT */
   7881     return BCM_E_NONE;
   7882 }
   7883 
   7884 /*
   7885  * Function:
   7886  *      _bcm_esw_l2_wb_sync
   7887  * Purpose:
   7888  *      Record L2 module persistent info for Level 2 Warm Boot
   7889  * Parameters:
   7890  *      unit - StrataSwitch unit number.
   7891  * Returns:
   7892  *      BCM_E_XXX
   7893  */
   7894 int
   7895 _bcm_esw_l2_wb_sync(int unit)
   7896 {
   7897 #if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT)
   7898     int                         sz = 0;
   7899     soc_scache_handle_t         scache_handle;
   7900     uint8                       *scache_ptr = NULL;
   7901     int                         aging_time = 0;
   7902     _bcm_l2_station_entry_t     **entry_arr;
   7903     _bcm_l2_station_control_t   *station_control = NULL;
   7904     int                         stable_size = 0;
   7905     int                         rv = BCM_E_NONE;
   7906     int                         index = 0;
   7907     int                         init_value = 0;
   7908     int                         sw_aging_support; /* SW Learning supported */
   7909     int                         underlay_max_entries = 0;
   7910 #ifdef BCM_RIOT_SUPPORT
   7911     int                         overlay_max_entries = 0;
   7912 #endif /* BCM_RIOT_SUPPORT */
   7913 
   7914 #if defined(BCM_TOMAHAWK3_SUPPORT)
   7915     if (SOC_IS_TOMAHAWK3(unit)) {
   7916         return _bcm_th3_l2_wb_sync(unit);
   7917     }
   7918 #endif /* BCM_TOMAHAWK3_SUPPORT */
   7919 
   7920     SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size));
   7921     /* Requires extended scache support warmboot */
   7922     if (stable_size == 0) {
   7923         return BCM_E_NONE;
   7924     }
   7925 
   7926     rv = _bcm_l2_station_control_get(unit, &station_control);
   7927     if (BCM_FAILURE(rv) && (rv != BCM_E_INIT)) {
   7928         return rv;
   7929     }
   7930 
   7931     sw_aging_support = SOC_IS_TRIUMPH3(unit);
   7932 #ifdef BCM_TOMAHAWK_SUPPORT
   7933     /* TH/TD3 does not support SW aging. Added only for warmboot upgrade purpose. */
   7934     sw_aging_support = sw_aging_support || SOC_IS_TOMAHAWKX(unit)  || SOC_IS_TRIDENT3X(unit);
   7935 #endif /* BCM_TOMAHAWK_SUPPORT */
   7936 #ifdef BCM_TRIDENT2_SUPPORT
   7937     sw_aging_support = sw_aging_support || SOC_CONTROL(unit)->l2x_sw_aging;
   7938 #endif /* BCM_TRIDENT2_SUPPORT */
   7939 
   7940     if (sw_aging_support ||
   7941         ((!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) && station_control)) {
   7942 
   7943         SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_L2, 0);
   7944         rv = _bcm_esw_scache_ptr_get(unit, scache_handle, FALSE,
   7945                                      0, &scache_ptr,
   7946                                      BCM_WB_DEFAULT_VERSION, NULL);
   7947 
   7948         if (BCM_FAILURE(rv) && (rv != BCM_E_INTERNAL)) {
   7949             return rv;
   7950         }
   7951 
   7952         if (sw_aging_support) {
   7953             /* aging time */
   7954             BCM_IF_ERROR_RETURN(
   7955                 _bcm_esw_l2_age_timer_get(unit, &aging_time));
   7956             sz = sizeof(int);
   7957             sal_memcpy(scache_ptr, &aging_time, sz);
   7958             scache_ptr += sz;
   7959         }
   7960 
   7961         if ((!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) && station_control) {
   7962             BCM_IF_ERROR_RETURN(
   7963                 _bcm_tr_l2_station_entry_max_size_get(unit, FALSE,
   7964                                                       &underlay_max_entries));
   7965             /* Underlay L2 station entry - sid/prio */
   7966             entry_arr = (station_control->entry_arr);
   7967 
   7968             for (index = 0; index < underlay_max_entries; index++) {
   7969                 if (entry_arr[index]) {
   7970                     sal_memcpy(scache_ptr,
   7971                                &(entry_arr[index]->sid), sizeof(int));
   7972                     scache_ptr += sizeof(int);
   7973 
   7974                     sal_memcpy(scache_ptr,
   7975                                &(entry_arr[index]->prio), sizeof(int));
   7976                     scache_ptr += sizeof(int);
   7977                 } else {
   7978                     sal_memcpy(scache_ptr, &init_value, sizeof(int));
   7979                     scache_ptr += sizeof(int);
   7980 
   7981                     sal_memcpy(scache_ptr, &init_value, sizeof(int));
   7982                     scache_ptr += sizeof(int);
   7983                 }
   7984             }
   7985 
   7986 #ifdef BCM_RIOT_SUPPORT
   7987             BCM_IF_ERROR_RETURN(
   7988                 _bcm_tr_l2_station_entry_max_size_get(unit, TRUE,
   7989                                                       &overlay_max_entries));
   7990             /* Overlay L2 station entry - sid/prio */
   7991             entry_arr = (station_control->entry_arr_2);
   7992 
   7993             for (index = 0; index < overlay_max_entries; index++) {
   7994                 if (entry_arr[index]) {
   7995                     sal_memcpy(scache_ptr,
   7996                                &(entry_arr[index]->sid), sizeof(int));
   7997                     scache_ptr += sizeof(int);
   7998 
   7999                     sal_memcpy(scache_ptr,
   8000                                &(entry_arr[index]->prio), sizeof(int));
   8001                     scache_ptr += sizeof(int);
   8002                 } else {
   8003                     sal_memcpy(scache_ptr, &init_value, sizeof(int));
   8004                     scache_ptr += sizeof(int);
   8005 
   8006                     sal_memcpy(scache_ptr, &init_value, sizeof(int));
   8007                     scache_ptr += sizeof(int);
   8008                 }
   8009             }
   8010 #endif /* BCM_RIOT_SUPPORT */
   8011         }
   8012     }
   8013 #endif /* BCM_TRIDENT_SUPPORT || BCM_GREYHOUND2_SUPPORT */
   8014     return BCM_E_NONE;
   8015 }
   8016 
   8017 /*
   8018  * Function:
   8019  *      _bcm_esw_l2_wb_recover
   8020  * Purpose:
   8021  *      Recover L2 module persistent info for Level 2 Warm Boot
   8022  * Parameters:
   8023  *      unit - StrataSwitch unit number.
   8024  * Returns:
   8025  *      BCM_E_XXX
   8026  */
   8027 STATIC int
   8028 _bcm_esw_l2_wb_recover(int unit)
   8029 {
   8030 #if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT)
   8031     soc_scache_handle_t         scache_handle;
   8032     uint8                       *scache_ptr = NULL;
   8033     uint16                      recovered_ver = 0;
   8034     int                         aging_time = 0;
   8035     int                         rv = BCM_E_NONE;
   8036     int                         additional_scache_size = 0;
   8037     int                         sw_aging_support; /* SW Learning supported */
   8038 #ifdef BCM_RIOT_SUPPORT
   8039     int                         overlay_max_entries = 0;
   8040 #endif /* BCM_RIOT_SUPPORT */
   8041     int                         underlay_max_entries = 0;
   8042     _bcm_l2_station_entry_t     **entry_arr;
   8043     _bcm_l2_station_control_t   *station_control = NULL;
   8044     int                         index = 0;
   8045     int                         sid = 0;
   8046     int                         pri = 0;
   8047     int                         cur_last_sid = 0;
   8048     int                         stable_size = 0;
   8049 
   8050     SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size));
   8051     /* Requires extended scache support warmboot */
   8052     if (stable_size == 0) {
   8053         return BCM_E_NONE;
   8054     }
   8055 
   8056     rv = _bcm_l2_station_control_get(unit, &station_control);
   8057     if (BCM_FAILURE(rv) && (rv != BCM_E_INIT)) {
   8058         return rv;
   8059     }
   8060 
   8061     sw_aging_support = SOC_IS_TRIUMPH3(unit);
   8062 #ifdef BCM_TOMAHAWK_SUPPORT
   8063     /* TH/TD3 does not support SW aging. Added only for warmboot upgrade purpose. */
   8064     sw_aging_support = sw_aging_support || SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit);
   8065 #endif /* BCM_TOMAHAWK_SUPPORT */
   8066 #ifdef BCM_TRIDENT2_SUPPORT
   8067     sw_aging_support = sw_aging_support || SOC_CONTROL(unit)->l2x_sw_aging;
   8068 #endif /* BCM_TRIDENT2_SUPPORT */
   8069 
   8070     if (sw_aging_support ||
   8071         ((!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) && station_control)) {
   8072 
   8073         SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_L2, 0);
   8074         rv = _bcm_esw_scache_ptr_get(unit, scache_handle, FALSE,
   8075                                      0, &scache_ptr,
   8076                                      BCM_WB_DEFAULT_VERSION, &recovered_ver);
   8077         if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) {
   8078             return rv;
   8079         } else if (BCM_E_NOT_FOUND == rv) {
   8080             return _bcm_esw_l2_wb_alloc(unit);
   8081         }
   8082 
   8083         if (scache_ptr != NULL) {
   8084             if (sw_aging_support) {
   8085                 if (recovered_ver >= BCM_WB_VERSION_1_0) {
   8086                     /* aging time */
   8087                     sal_memcpy(&aging_time, scache_ptr, sizeof(int));
   8088                     BCM_IF_ERROR_RETURN(
   8089                         _bcm_esw_l2_age_timer_set(unit, aging_time, aging_time > 0));
   8090                     scache_ptr += sizeof(int);
   8091                 } else {
   8092                     additional_scache_size += sizeof(int);
   8093                 }
   8094             }
   8095 
   8096             if ((!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) && station_control) {
   8097                 BCM_IF_ERROR_RETURN(
   8098                     _bcm_tr_l2_station_entry_max_size_get(
   8099                         unit, FALSE, &underlay_max_entries));
   8100 #ifdef BCM_RIOT_SUPPORT
   8101                 BCM_IF_ERROR_RETURN(
   8102                     _bcm_tr_l2_station_entry_max_size_get(
   8103                         unit, TRUE, &overlay_max_entries));
   8104 #endif /* BCM_RIOT_SUPPORT */
   8105 
   8106                 /* Recover overlay/underlay L2 station entry */
   8107                 if (recovered_ver >= BCM_WB_VERSION_1_1) {
   8108                     entry_arr = (station_control->entry_arr);
   8109 
   8110                     for (index = 0; index < underlay_max_entries; index++) {
   8111                         sal_memcpy(&sid, scache_ptr, sizeof(int));
   8112                         scache_ptr += sizeof(int);
   8113 
   8114                         sal_memcpy(&pri, scache_ptr, sizeof(int));
   8115                         scache_ptr += sizeof(int);
   8116 
   8117                         if (sid > cur_last_sid) {
   8118                             cur_last_sid = sid;
   8119                         }
   8120 
   8121                         if (entry_arr[index]) {
   8122                             if (0 == sid) {
   8123                                 /*
   8124                                  * Only recover the L2 station entries created
   8125                                  * by bcm_l2_station APIs
   8126                                  */
   8127                                 if (index < station_control->entries_total) {
   8128                                     if (NULL != entry_arr[index]->tcam_ent) {
   8129                                         sal_free(entry_arr[index]->tcam_ent);
   8130                                     }
   8131 
   8132                                     sal_free(entry_arr[index]);
   8133 
   8134                                     entry_arr[index] = NULL;
   8135                                     station_control->entry_count--;
   8136                                     station_control->entries_free++;
   8137                                 }
   8138                             } else {
   8139                                 entry_arr[index]->sid = sid;
   8140                                 entry_arr[index]->prio = pri;
   8141                             }
   8142                         }
   8143                     }
   8144 
   8145                     rv = _bcm_tr_l2_station_entry_last_sid_set(unit, FALSE,
   8146                                                           cur_last_sid);
   8147                     if (BCM_FAILURE(rv)) {
   8148                        return rv;
   8149                     }
   8150 #ifdef BCM_RIOT_SUPPORT
   8151                     cur_last_sid = 0;
   8152 
   8153                     entry_arr = (station_control->entry_arr_2);
   8154 
   8155                     for (index = 0; index < overlay_max_entries; index++) {
   8156                         sal_memcpy(&sid, scache_ptr, sizeof(int));
   8157                         scache_ptr += sizeof(int);
   8158 
   8159                         sal_memcpy(&pri, scache_ptr, sizeof(int));
   8160                         scache_ptr += sizeof(int);
   8161 
   8162                         if (sid > cur_last_sid) {
   8163                             cur_last_sid = sid;
   8164                         }
   8165 
   8166                         if (entry_arr[index]) {
   8167                             if (0 == sid) {
   8168                                 /*
   8169                                  * Only recover the L2 station entries created
   8170                                  * by bcm_l2_station APIs
   8171                                  */
   8172                                 if (index < station_control->entries_total_2) {
   8173                                     if (NULL != entry_arr[index]->tcam_ent) {
   8174                                         sal_free(entry_arr[index]->tcam_ent);
   8175                                     }
   8176                                     sal_free(entry_arr[index]);
   8177                                     entry_arr[index] = NULL;
   8178                                     station_control->entry_count_2--;
   8179                                     station_control->entries_free_2++;
   8180                                 }
   8181                             } else {
   8182                                 entry_arr[index]->sid = sid;
   8183                                 entry_arr[index]->prio = pri;
   8184                             }
   8185                         }
   8186                     }
   8187 
   8188                     rv = _bcm_tr_l2_station_entry_last_sid_set(unit, TRUE,
   8189                                                           cur_last_sid);
   8190                     if (BCM_FAILURE(rv)) {
   8191                        return rv;
   8192                     }
   8193 #endif /* BCM_RIOT_SUPPORT */
   8194                 } else {
   8195                     /* Underlay L2 station entry - sid/prio */
   8196                     additional_scache_size +=
   8197                         (underlay_max_entries *(sizeof(int) * 2));
   8198 #ifdef BCM_RIOT_SUPPORT
   8199                     /* Overlay L2 station entry - sid/prio */
   8200                     additional_scache_size +=
   8201                         (overlay_max_entries * (sizeof(int) * 2));
   8202 #endif /* BCM_RIOT_SUPPORT */
   8203                 }
   8204             }
   8205 
   8206             if (additional_scache_size > 0) {
   8207                 rv = soc_scache_realloc(unit, scache_handle,
   8208                                         additional_scache_size);
   8209                 if(BCM_FAILURE(rv)) {
   8210                    return rv;
   8211                 }
   8212             }
   8213         }
   8214     }
   8215 #endif /* BCM_TRIDENT_SUPPORT || BCM_GREYHOUND2_SUPPORT */
   8216     return BCM_E_NONE;
   8217 }
   8218 
   8219 #endif /* BCM_WARM_BOOT_SUPPORT */
   8220