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


      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 #ifdef BCM_WARM_BOOT_SUPPORT
     18 #include <soc/scache.h>
     19 #endif /* BCM_WARM_BOOT_SUPPORT */
     20 
     21 #include <bcm/l2.h>
     22 #include <bcm/error.h>
     23 
     24 #include <bcm_int/esw/mbcm.h>
     25 #include <bcm_int/esw/l2.h>
     26 #include <bcm_int/esw/vlan.h>
     27 #include <bcm_int/esw/trunk.h>
     28 #if defined(BCM_TRX_SUPPORT)
     29 #include <bcm_int/esw/trx.h>
     30 #endif /* BCM_TRX_SUPPORT */
     31 #include <bcm_int/esw/mpls.h>
     32 #include <bcm_int/esw/trident.h>
     33 #ifdef BCM_TOMAHAWK3_SUPPORT
     34 #include <soc/tomahawk3.h>
     35 #include <bcm_int/esw/tomahawk3.h>
     36 #endif /* BCM_TOMAHAWK3_SUPPORT */
     37 #ifdef BCM_WARM_BOOT_SUPPORT
     38 #include <bcm_int/esw/switch.h>
     39 #endif /* BCM_WARM_BOOT_SUPPORT */
     40 
     41 #include <bcm_int/esw_dispatch.h>
     42 
     43 #ifdef BCM_TOMAHAWK3_SUPPORT                                                    
     44 /****************************************************************
     45  *
     46  * L2 software tables, per unit.
     47  */
     48 
     49 int _th3_l2_init[BCM_MAX_NUM_UNITS];
     50 
     51 static _bcm_l2_match_ctrl_t *_bcm_th3_l2_match_ctrl[BCM_MAX_NUM_UNITS];
     52 static sal_sem_t _bcm_th3_l2_cb_check[BCM_MAX_NUM_UNITS];
     53 
     54 /****************************************************************************
     55  *
     56  * L2X Message Registration
     57  */
     58 
     59 #define L2_CB_MAX		3
     60 
     61 typedef struct th3_l2x_cb_entry_s {
     62     bcm_l2_addr_callback_t	fn;
     63     void			*fn_data;
     64 } th3_l2_cb_entry_t;
     65 
     66 #define _BCM_TH3_L2X_THREAD_STOP      (1 << 0)
     67 typedef struct th3_l2_data_s {
     68     th3_l2_cb_entry_t cb[L2_CB_MAX];
     69     int               cb_count;
     70     int               flags;
     71     sal_mutex_t       l2_mutex;
     72 } th3_l2_data_t;
     73 
     74 static th3_l2_data_t th3_l2_data[SOC_MAX_NUM_DEVICES];
     75 
     76 
     77 #define L2_LOCK(unit) \
     78     sal_mutex_take(th3_l2_data[unit].l2_mutex, sal_mutex_FOREVER)
     79 
     80 #define L2_UNLOCK(unit) sal_mutex_give(th3_l2_data[unit].l2_mutex)
     81 
     82 #define L2_MUTEX(unit) if (th3_l2_data[unit].l2_mutex == NULL && \
     83        (th3_l2_data[unit].l2_mutex = sal_mutex_create("bcm_l2_lock")) == NULL) \
     84             return BCM_E_MEMORY
     85 
     86 /****************************************************************************
     87  *
     88  * L2 Callbacks Registration
     89  */
     90 static bcm_l2_addr_callback_t _bcm_th3_l2_cbs[SOC_MAX_NUM_DEVICES];
     91 static void *_bcm_th3_l2_cb_data[SOC_MAX_NUM_DEVICES];
     92 
     93 /* forward declaration */
     94 #if 0
     95 
     96 static int _bcm_l2_bpdu_init(int unit);
     97 #endif
     98 STATIC int _bcm_th3_l2_replace(int unit, uint32 flags, uint32 int_flags,
     99                                bcm_l2_addr_t *match_addr,
    100                                bcm_module_t new_module, bcm_port_t new_port,
    101                                bcm_trunk_t new_trunk,
    102                                bcm_l2_traverse_cb trav_fn, void *user_data);
    103 
    104 /* L2 (vlan, port) tuple structure */
    105 typedef struct _bcm_l2_vlan_port_pair_s {
    106     /* Array of PBMP with max VLAN size, the first 0-4095 PBMP entries 
    107      in the array are for max number of VLANs supported, the 4096th
    108      i.e pbm[BCM_VLAN_MAX+1]th entry in the array is to maintain a list
    109      of PBMPs for invalid VLANs (used for delete by gport operation). */
    110     bcm_pbmp_t        pbm[BCM_VLAN_MAX+2];
    111 } _bcm_l2_vlan_port_pair_t;
    112 
    113 typedef struct _bcm_l2_vlan_trunk_pair_s {
    114     SHR_BITDCL        *tbm[BCM_VLAN_MAX+2];
    115 } _bcm_l2_vlan_trunk_pair_t;
    116 
    117 typedef struct _bcm_l2_del_vlan_port_pair_s {
    118     uint32                    flags;            /* BCM_L2_AUTH_XXX flags. */
    119     uint32                    replace_flags;        /* BCM_L2_REPLACE_XXX flags */
    120     bcm_vlan_vector_t         del_by_vlan_vec;  /* Vlan vector represents 
    121                                                    delete by vlan */
    122     _bcm_l2_vlan_port_pair_t  *mod_pair_arr;    /* Reference to Array of
    123                                                    (vlan,port) for max modules */
    124     _bcm_l2_vlan_trunk_pair_t *unit_pair_arr;   /* Reference to Array of
    125                                                    (vlan,tid) for each unit */
    126 } _bcm_l2_del_vlan_port_pair_t;
    127 
    128 typedef enum l2x_memacc_field_e {
    129     _BCM_L2_MEMACC_VALID,
    130     _BCM_L2_MEMACC_KEY_TYPE,
    131     _BCM_L2_MEMACC_NUM
    132 } l2x_memacc_field_t;
    133 
    134 static uint32 _l2_dbg_matched_entries[SOC_MAX_NUM_DEVICES],
    135               _l2_dbg_unmatched_entries[SOC_MAX_NUM_DEVICES];
    136 
    137 #ifdef BCM_WARM_BOOT_SUPPORT
    138 STATIC int _bcm_th3_l2_wb_alloc(int unit);
    139 STATIC int _bcm_th3_l2_wb_recover(int unit);
    140 #endif /* BCM_WARM_BOOT_SUPPORT */
    141 
    142 /* just need to clear SRC or DES hit bit. Customers may call API bcm_esw_l2_replace
    143 *  with parameter *match_addr which value is NULL */
    144 #define _CLEAR_ALL_ENTRIES_SRC_OR_DES_HIT_BIT(flag) \
    145                   (!(flag & (BCM_L2_REPLACE_MATCH_VLAN |\
    146                              BCM_L2_REPLACE_MATCH_MAC |\
    147                              BCM_L2_REPLACE_MATCH_DEST)) &&\
    148                    (flag & (BCM_L2_REPLACE_DES_HIT_CLEAR |\
    149                             BCM_L2_REPLACE_SRC_HIT_CLEAR)))
    150 
    151 /*
    152  * Function:
    153  *	bcm_th3_l2_learn_start
    154  * Description:
    155  *	This function creates learn thread. It is called after L2 learn cache has
    156  *  and CMICx have been initialized
    157  * Parameters:
    158  *	unit - StrataSwitch device unit number
    159  * Returns:
    160  *	BCM_E_XXX
    161  */
    162 int
    163 bcm_th3_l2_learn_start(int unit, int interval)
    164 {
    165     sal_usecs_t cfg_interval = -1;
    166     int rv = SOC_E_NONE;
    167 
    168     /* Stop learn thread if it is runnng, and apply new interval provided
    169      * by application
    170      */
    171     if (soc_th3_l2_learn_thread_running(unit, &cfg_interval)) {
    172         LOG_ERROR(BSL_LS_BCM_L2,
    173                  (BSL_META_U(unit, "Learn thread running, interval=%d\n"),
    174                  cfg_interval));
    175 
    176         soc_th3_l2_learn_thread_stop(unit);
    177         /* Check if sleep is reqd */
    178         sal_usleep(10000);
    179     }
    180 
    181     LOG_INFO(BSL_LS_BCM_L2, (BSL_META_U(unit, "======: Starting learn"
    182                                               " thread\n")));
    183 
    184     rv = soc_th3_l2_learn_alloc_resources(unit);
    185 
    186     if (rv == SOC_E_NONE) {
    187         rv = soc_th3_l2_learn_thread_start(unit, interval);
    188     }
    189 
    190     return rv;
    191 }
    192 
    193 /*
    194  * Function:
    195  *	bcm_tomahawk3_l2_init
    196  * Description:
    197  *	Perform required initializations to L2 table.
    198  * Parameters:
    199  *	unit - StrataSwitch PCI device unit number (driver internal).
    200  * Returns:
    201  *	BCM_E_XXX
    202  */
    203 
    204 int
    205 bcm_tomahawk3_l2_init(int unit)
    206 {
    207     int rv; 
    208     sal_usecs_t lrn_interval;
    209     sal_usecs_t l2x_interval;
    210     uint32 flags = 0;
    211 #ifdef BCM_XGS_SWITCH_SUPPORT
    212     int frozen;
    213 
    214     BCM_IF_ERROR_RETURN(
    215         soc_l2x_is_frozen(unit, SOC_L2X_FROZEN_WITH_LOCK, &frozen));
    216     if (TRUE == frozen) {
    217         return BCM_E_BUSY;
    218     }
    219 #endif /* BCM_XGS_SWITCH_SUPPORT */
    220     _th3_l2_init[unit] = 0;
    221 
    222     if (!SOC_WARM_BOOT(unit) && !SOC_IS_RCPU_ONLY(unit)) {
    223         /* Turn off arl aging */
    224         BCM_IF_ERROR_RETURN
    225             (SOC_FUNCTIONS(unit)->soc_age_timer_set(unit, 0, 0));
    226         BCM_IF_ERROR_RETURN(bcm_tomahawk3_l2_detach(unit));
    227     }
    228 
    229     /* Proposal: during warm boot, customer wants to freeze l2x.
    230      * After warm boot, customer will restore l2x.
    231      */
    232     if (SOC_WARM_BOOT(unit) && soc_l2x_cml_override_is_enabled(unit)) {
    233         /* In this condition, soc_l2x_freeze does not change ING_MISC_CONFIG2r.
    234          * It just wants to Increment  l2 frozen indicator "f_l2->hw_frozen++".
    235          * When we call bcm_tomahawk3_l2_age_timer_set, we won't enable SW aging
    236          * by mistake
    237          */
    238         BCM_IF_ERROR_RETURN(soc_l2x_selective_freeze(unit,
    239                                 SOC_L2X_FROZEN_WITHOUT_LOCK));
    240     }
    241 
    242     /*
    243      * Call chip-dependent initialization
    244      */
    245     BCM_IF_ERROR_RETURN
    246         (mbcm_driver[unit]->mbcm_l2_init(unit));
    247 
    248     if (!SOC_WARM_BOOT(unit) && !SOC_IS_RCPU_ONLY(unit)) {
    249         /*
    250          * Init L2 cache
    251          */
    252         rv = bcm_th3_l2_cache_init(unit);
    253         if (BCM_FAILURE(rv) && (rv != BCM_E_UNAVAIL)) {
    254             return rv;
    255         }
    256     }
    257 
    258     /* If learn thread is not running, start it */
    259     if (!(soc_th3_l2_learn_thread_running(unit, &lrn_interval))) {
    260          int cfg_interval;
    261 
    262         /* Start learn thread. Make sure learn cache and DMA infrastructure
    263          * have been initialized at this point
    264          */
    265         cfg_interval = soc_property_get(unit, spn_L2XLRN_THREAD_INTERVAL,
    266                                         SAL_BOOT_BCMSIM ?
    267                                         BCMSIM_L2XLRN_INTERVAL :
    268                                         BCM_L2XLRN_INTERVAL_DEFAULT);
    269 
    270         BCM_IF_ERROR_RETURN(bcm_th3_l2_learn_start(unit, cfg_interval));
    271     }
    272 
    273     /* If l2x thread is not running, start it */
    274     if (!soc_l2x_running(unit, &flags, &l2x_interval)) {
    275         l2x_interval = soc_property_get(unit, spn_L2XMSG_THREAD_USEC,
    276                                         SOC_L2X_INTERVAL_DEFAULT);
    277         rv = soc_l2x_start(unit, 0, l2x_interval);
    278 
    279         if (BCM_FAILURE(rv)) {
    280 
    281             LOG_ERROR(BSL_LS_BCM_L2,
    282                      (BSL_META_U(unit, "Could not start l2x thread,"
    283                       "rv = %d, interval=%d\n"), rv, l2x_interval));
    284 
    285             return rv;
    286         }
    287     }
    288 
    289 #ifdef BCM_WARM_BOOT_SUPPORT
    290     if (SOC_WARM_BOOT(unit)) {
    291         BCM_IF_ERROR_RETURN(_bcm_th3_l2_wb_recover(unit));
    292     } else {
    293         BCM_IF_ERROR_RETURN(_bcm_th3_l2_wb_alloc(unit));
    294     }
    295 #endif /* BCM_WARM_BOOT_SUPPORT */
    296 
    297     if (_bcm_th3_l2_cb_check[unit] == NULL) {
    298         _bcm_th3_l2_cb_check[unit] = sal_sem_create("l2 callback check",
    299                                                     sal_sem_BINARY, 1);
    300         if (_bcm_th3_l2_cb_check[unit] == NULL) {
    301             return BCM_E_MEMORY;
    302         }
    303     }
    304 
    305     _th3_l2_init[unit] = 1;
    306     return BCM_E_NONE;
    307 }
    308 
    309 /*
    310  * Function:
    311  *      bcm_tomahawk3_l2_detach
    312  * Purpose:
    313  *      Clean up L2 bcm layer when unit is detached
    314  * Parameters:
    315  *      unit - Unit being detached
    316  * Returns:
    317  *	BCM_E_XXX
    318  */
    319 int
    320 bcm_tomahawk3_l2_detach(int unit)
    321 {
    322     int frozen;
    323 
    324     /* Verify the table is not frozen */
    325     BCM_IF_ERROR_RETURN(soc_l2x_is_frozen(unit, SOC_L2X_FROZEN_WITH_LOCK,
    326                                           &frozen));
    327     if (TRUE == frozen) {
    328         return BCM_E_BUSY;
    329     }
    330 
    331     if (_bcm_th3_l2_match_ctrl[unit] &&
    332         _bcm_th3_l2_match_ctrl[unit]->preserved) {
    333         _th3_l2_init[unit] = 0;
    334         return BCM_E_NONE;
    335     }
    336 
    337     /*
    338      * Call chip-dependent finalization
    339      */
    340     SOC_IF_ERROR_RETURN(mbcm_driver[unit]->mbcm_l2_term(unit));
    341 
    342     if (_bcm_th3_l2_cb_check[unit] != NULL) {
    343         sal_sem_destroy(_bcm_th3_l2_cb_check[unit]);
    344         _bcm_th3_l2_cb_check[unit] = NULL;
    345     }
    346 
    347     _th3_l2_init[unit] = 0;
    348 
    349     return BCM_E_NONE;
    350 }
    351 
    352 /*
    353  * Function:
    354  *     _bcm_l2_match_ctrl_init
    355  * Purpose:
    356  *     Allocate resources for match control data (used by callback
    357  *     registration, traverse and replace APIs)
    358  * Parameters:
    359  *     unit  - (IN) BCM device number
    360  * Retruns:
    361  *     BCM_E_NONE on success
    362  *     Other BCM_E_XXX codes on error
    363  */
    364 int
    365 _bcm_l2_match_ctrl_init(int unit)
    366 {
    367     sal_sem_t sem = NULL;
    368 
    369     if (_bcm_th3_l2_match_ctrl[unit] == NULL) {
    370         _bcm_th3_l2_match_ctrl[unit] = sal_alloc(sizeof(_bcm_l2_match_ctrl_t),
    371                                              "matched_traverse control");
    372         if (_bcm_th3_l2_match_ctrl[unit] == NULL) {
    373             return BCM_E_MEMORY;
    374         }
    375         sem = sal_sem_create("L2_matched", sal_sem_BINARY, 0);
    376         if (sem == NULL) {
    377             sal_free(_bcm_th3_l2_match_ctrl[unit]);
    378             _bcm_th3_l2_match_ctrl[unit] = NULL;
    379             return BCM_E_RESOURCE;
    380         }
    381     } else {
    382         sem = _bcm_th3_l2_match_ctrl[unit]->sem;
    383     }
    384 
    385     sal_memset(_bcm_th3_l2_match_ctrl[unit], 0, sizeof(_bcm_l2_match_ctrl_t));
    386     _bcm_th3_l2_match_ctrl[unit]->sem = sem;
    387 
    388     return BCM_E_NONE;
    389 }
    390 
    391 /*
    392  * Function:
    393  *     _bcm_l2_match_ctrl_deinit
    394  * Purpose:
    395  *     Free resources allocated for match control data (used by callback
    396  *     registration, traverse and replace APIs)
    397  * Parameters:
    398  *     unit  - (IN) BCM device number
    399  * Retruns:
    400  *     No value
    401  */
    402 void
    403 _bcm_l2_match_ctrl_deinit(int unit)
    404 {
    405 
    406     if (_bcm_th3_l2_match_ctrl[unit] != NULL) {
    407        if (_bcm_th3_l2_match_ctrl[unit]->sem != NULL) {
    408           sal_sem_destroy(_bcm_th3_l2_match_ctrl[unit]->sem);
    409           _bcm_th3_l2_match_ctrl[unit]->sem = NULL;
    410        }
    411        sal_free(_bcm_th3_l2_match_ctrl[unit]);
    412       _bcm_th3_l2_match_ctrl[unit] = NULL;
    413     }
    414 
    415     return;
    416 }
    417 
    418 int _bcm_tomahawk3_l2_age_timer_set(int unit, int age_seconds, int enabled)
    419 {
    420     int rv;
    421 #ifdef BCM_XGS_SWITCH_SUPPORT
    422     int         frozen = 0;
    423 #endif
    424 
    425     SOC_L2X_MEM_LOCK(unit);
    426 #ifdef BCM_XGS_SWITCH_SUPPORT
    427     rv = soc_l2x_is_frozen(unit, SOC_L2X_FROZEN, &frozen);
    428 
    429     if (frozen) {
    430         soc_age_timer_cache_set(unit, age_seconds, enabled);
    431         enabled = 0; /* L2x is frozen, so we can't enable aging function */
    432     } 
    433 #endif
    434 
    435     rv = SOC_FUNCTIONS(unit)->soc_age_timer_set(unit, age_seconds, enabled);
    436     SOC_L2X_MEM_UNLOCK(unit);
    437     return rv;
    438 }
    439 
    440 /*
    441  * Function:
    442  *	bcm_tomahawk3_l2_age_timer_set
    443  * Description:
    444  *	Set the age timer for all blocks.
    445  *	Setting the value to 0 disables the age timer.
    446  * Parameters:
    447  *	unit - StrataSwitch PCI device unit number (driver internal).
    448  *	age_seconds - Age timer value in seconds
    449  * Returns:
    450  *	BCM_E_NONE		Success
    451  *	BCM_E_INTERNAL		Chip access failure
    452  */
    453 
    454 int
    455 bcm_tomahawk3_l2_age_timer_set(int unit, int age_seconds)
    456 {
    457     int			max_value;
    458     int			enabled;
    459     int			rv;
    460 
    461     TH3_L2_INIT(unit);
    462 
    463     BCM_IF_ERROR_RETURN
    464 	(SOC_FUNCTIONS(unit)->soc_age_timer_max_get(unit, &max_value));
    465 
    466     if (age_seconds < 0 || age_seconds > max_value) {
    467         return BCM_E_PARAM;
    468     }
    469 
    470     enabled = age_seconds ? 1 : 0;
    471 
    472     rv = _bcm_tomahawk3_l2_age_timer_set(unit, age_seconds, enabled);
    473 
    474     return rv;
    475 }
    476 
    477 int
    478 _bcm_tomahawk3_l2_age_timer_get(int unit, int *age_seconds)
    479 {
    480     int         rv = BCM_E_NONE;
    481 #ifdef BCM_XGS_SWITCH_SUPPORT
    482     int         frozen = 0;
    483 #endif
    484     int         enabled;
    485 
    486     SOC_L2X_MEM_LOCK(unit);
    487 
    488 #ifdef BCM_XGS_SWITCH_SUPPORT
    489     rv = soc_l2x_is_frozen(unit, SOC_L2X_FROZEN, &frozen);
    490 
    491     if (BCM_FAILURE(rv)) {
    492         frozen = 0;
    493     }
    494     if (frozen) {
    495         soc_age_timer_cache_get(unit, age_seconds, &enabled);
    496 
    497         SOC_L2X_MEM_UNLOCK(unit);
    498         return rv;
    499     }
    500 #endif
    501     rv = SOC_FUNCTIONS(unit)->soc_age_timer_get(unit, age_seconds, &enabled);
    502 
    503     SOC_L2X_MEM_UNLOCK(unit);
    504     return rv;
    505 }
    506 
    507 /*
    508  * Function: bcm_tomahawk3_l2_age_timer_get
    509  * Description:
    510  *	Returns the current age timer value
    511  *	The value is 0 if aging is not enabled
    512  * Parameters:
    513  *	unit - StrataSwitch PCI device unit number (driver internal)
    514  *	age_seconds - Place to store returned age timer value in seconds
    515  * Returns:
    516  *	BCM_E_NONE		Success
    517  *	BCM_E_INTERNAL		Chip access failure
    518  */
    519 
    520 int
    521 bcm_tomahawk3_l2_age_timer_get(int unit, int *age_seconds)
    522 {
    523     int			seconds, enabled;
    524     int			rv;
    525 
    526     TH3_L2_INIT(unit);
    527 
    528     if (age_seconds == NULL) {
    529         return BCM_E_PARAM;
    530     }
    531 
    532     SOC_L2X_MEM_LOCK(unit);
    533     rv = SOC_FUNCTIONS(unit)->soc_age_timer_get(unit, &seconds, &enabled);
    534     SOC_L2X_MEM_UNLOCK(unit);
    535 
    536     BCM_IF_ERROR_RETURN(rv);
    537 
    538     if (enabled) {
    539         *age_seconds = seconds;
    540     } else {
    541         *age_seconds = 0;
    542     }
    543 
    544     return BCM_E_NONE;
    545 }
    546 
    547 /*
    548  * Function:
    549  *      _bcm_th3_l2_register_callback
    550  * Description:
    551  *      Call back to handle bcm_l2_addr_register clients
    552  * Parameters:
    553  *      unit - StrataSwitch unit number.
    554  *      entry_del - Entry to be deleted or updated, NULL if none
    555  *      entry_add - Entry to be inserted or updated, NULL if none
    556  *      fn_data - unused
    557  * Notes:
    558  *      Only one callback per unit to the bcm layer is supported here.
    559  *      Multiple bcm client callbacks per unit are supported in the bcm layer
    560  */
    561 void
    562 _bcm_th3_l2_register_callback(int unit,
    563                               int pflags,
    564                               l2x_entry_t *entry_del,
    565                               l2x_entry_t *entry_add,
    566                               void *fn_data)
    567 {
    568     bcm_l2_addr_t l2addr_del, l2addr_add;
    569     _bcm_l2_match_ctrl_t *match_ctrl;
    570     l2x_entry_t *l2x_entry_buf;
    571     int buf_index, entry_index;
    572 
    573     if (pflags & (SOC_L2X_ENTRY_DUMMY | SOC_L2X_ENTRY_NO_ACTION)) {
    574         /* pass l2addr_add info match */
    575         match_ctrl = _bcm_th3_l2_match_ctrl[unit];
    576         buf_index = match_ctrl->entry_wr_idx / _BCM_L2_MATCH_ENTRY_BUF_SIZE;
    577         entry_index = match_ctrl->entry_wr_idx % _BCM_L2_MATCH_ENTRY_BUF_SIZE;
    578         if (entry_index == 0) {
    579             if (buf_index >= _BCM_L2_MATCH_ENTRY_BUF_COUNT) {
    580                 return;
    581             }
    582             match_ctrl->l2x_entry_buf[buf_index] =
    583                 sal_alloc(sizeof(l2x_entry_t) * _BCM_L2_MATCH_ENTRY_BUF_SIZE,
    584                           "l2_matched_traverse");
    585             if (match_ctrl->l2x_entry_buf[buf_index] == NULL) {
    586                 return;
    587             }
    588         }
    589         l2x_entry_buf = match_ctrl->l2x_entry_buf[buf_index];
    590 
    591         if (pflags & SOC_L2X_ENTRY_NO_ACTION) {
    592             l2x_entry_buf[entry_index] = *entry_add;
    593         } else {
    594             sal_memcpy(&l2x_entry_buf[entry_index],
    595                        soc_mem_entry_null(unit, L2Xm), sizeof(l2x_entry_t));
    596         }
    597         match_ctrl->entry_wr_idx++;
    598         sal_sem_give(match_ctrl->sem);
    599         sal_thread_yield();
    600     } else if (_bcm_th3_l2_cbs[unit] != NULL) {
    601          uint32 flags = 0; /* Common flags: Move, From/to native */
    602 
    603         sal_memset(&l2addr_del, 0, sizeof(bcm_l2_addr_t));
    604         sal_memset(&l2addr_add, 0, sizeof(bcm_l2_addr_t));
    605 
    606         /* First, set up the entries:  decode HW entries and set flags */
    607         if (entry_del != NULL) {
    608             (void)_bcm_th3_l2_from_l2x(unit, &l2addr_del, entry_del);
    609         }
    610         if (entry_add != NULL) {
    611             (void)_bcm_th3_l2_from_l2x(unit, &l2addr_add, entry_add);
    612         }
    613 
    614         if ((entry_del != NULL) && (entry_add != NULL)) { /* It's a move */
    615             flags |= BCM_L2_MOVE;
    616             if (SOC_USE_GPORT(unit)) {
    617                 if (l2addr_del.port != l2addr_add.port) {
    618                     flags |= BCM_L2_MOVE_PORT;
    619                 }
    620             } else {
    621                 if (l2addr_del.modid != l2addr_add.modid ||
    622                     l2addr_del.tgid != l2addr_add.tgid ||
    623                     l2addr_del.port != l2addr_add.port) {
    624                     flags |= BCM_L2_MOVE_PORT;
    625                 }
    626             }
    627             if (!(l2addr_del.flags & BCM_L2_TRUNK_MEMBER)) {
    628                 if (bcm_tomahawk3_l2_port_native(unit, l2addr_del.modid,
    629                                                  l2addr_del.port) > 0) {
    630                     flags |= BCM_L2_FROM_NATIVE;
    631                     l2addr_del.flags |= BCM_L2_NATIVE;
    632                 }
    633             }
    634             if (!(l2addr_add.flags & BCM_L2_TRUNK_MEMBER)) {
    635                 if (bcm_tomahawk3_l2_port_native(unit, l2addr_add.modid,
    636                                                  l2addr_add.port) > 0) {
    637                     flags |= BCM_L2_TO_NATIVE;
    638                     l2addr_add.flags |= BCM_L2_NATIVE;
    639                 }
    640             }
    641             l2addr_del.flags |= flags;
    642             l2addr_add.flags |= flags;
    643         } else if (entry_del != NULL) { /* Age out or simple delete */
    644             if (!(l2addr_del.flags & BCM_L2_TRUNK_MEMBER)) {
    645                 if (bcm_tomahawk3_l2_port_native(unit, l2addr_del.modid,
    646                                                  l2addr_del.port) > 0) {
    647                     l2addr_del.flags |= BCM_L2_NATIVE;
    648                 }
    649             }
    650         } else if (entry_add != NULL) { /* Insert or learn */
    651             if (!(l2addr_add.flags & BCM_L2_TRUNK_MEMBER)) {
    652                 if (bcm_tomahawk3_l2_port_native(unit, l2addr_add.modid,
    653                                                  l2addr_add.port) > 0) {
    654                     l2addr_add.flags |= BCM_L2_NATIVE;
    655                 }
    656             }
    657         }
    658 
    659         if (_bcm_th3_l2_cb_check[unit] != NULL) {
    660             sal_sem_take(_bcm_th3_l2_cb_check[unit], sal_sem_FOREVER);
    661         }
    662 
    663         /* The entries are now set up. Make the callbacks */
    664         if (entry_del != NULL) {
    665             if (_bcm_th3_l2_cbs[unit] != NULL) {
    666                 _bcm_th3_l2_cbs[unit](unit, &l2addr_del, 0,
    667                                       _bcm_th3_l2_cb_data[unit]);
    668             }
    669         }
    670 
    671         if (pflags & SOC_L2X_ENTRY_OVERFLOW) {
    672             l2addr_add.flags |= BCM_L2_ENTRY_OVERFLOW;
    673         }
    674 
    675         if (entry_add != NULL) {
    676             if (_bcm_th3_l2_cbs[unit] != NULL) {
    677                 _bcm_th3_l2_cbs[unit](unit, &l2addr_add, 1,
    678                                       _bcm_th3_l2_cb_data[unit]);
    679             }
    680         }
    681 
    682         if (_bcm_th3_l2_cb_check[unit] != NULL) {
    683             sal_sem_give(_bcm_th3_l2_cb_check[unit]);
    684         }
    685     }
    686 }
    687 
    688 /*
    689  * Function:
    690  *	bcm_tomahawk3_l2_addr_freeze
    691  * Description:
    692  *	Temporarily quiesce ARL from all activity (learning, aging, inserting)
    693  * include SW operations
    694  * Parameters:
    695  *	unit - StrataSwitch PCI device unit number (driver internal).
    696  * Returns:
    697  *	BCM_E_NONE		Success
    698  *	BCM_E_INTERNAL		Chip access failure
    699  */
    700 
    701 int
    702 bcm_tomahawk3_l2_addr_freeze(int unit)
    703 {
    704     TH3_L2_INIT(unit);
    705 
    706 #ifdef BCM_XGS_SWITCH_SUPPORT
    707     if (soc_feature(unit, soc_feature_arl_hashed)) {
    708         return soc_l2x_freeze(unit);
    709     }
    710 #endif
    711 
    712     return BCM_E_UNAVAIL;
    713 }
    714 
    715 /*
    716  * Function:
    717  *	bcm_tomahawk3_l2_addr_thaw
    718  * Description:
    719  *	Restore normal ARL activity including S/W and H/W activity.
    720  * Parameters:
    721  *	unit - StrataSwitch PCI device unit number (driver internal).
    722  * Returns:
    723  *	BCM_E_NONE		Success
    724  *	BCM_E_INTERNAL		Chip access failure
    725  */
    726 
    727 int
    728 bcm_tomahawk3_l2_addr_thaw(int unit)
    729 {
    730     TH3_L2_INIT(unit);
    731 
    732 #ifdef BCM_XGS_SWITCH_SUPPORT
    733     if (soc_feature(unit, soc_feature_arl_hashed)) {
    734         return soc_l2x_thaw(unit);
    735     }
    736 #endif
    737 
    738     return BCM_E_UNAVAIL;
    739 }
    740 
    741 /*
    742  * Function:
    743  *      bcm_tomahawk3_l2_clear
    744  * Purpose:
    745  *      Clear the L2 layer
    746  * Parameters:
    747  *      unit  - BCM unit number
    748  * Returns:
    749  *      BCM_E_XXX
    750  */
    751 
    752 int
    753 bcm_tomahawk3_l2_clear(int unit)
    754 {
    755     TH3_L2_INIT(unit);
    756 
    757     if (_bcm_th3_l2_match_ctrl[unit]) {
    758         _bcm_th3_l2_match_ctrl[unit]->preserved = 1;
    759     }
    760 
    761     BCM_IF_ERROR_RETURN(bcm_tomahawk3_l2_detach(unit));
    762 
    763     if (_bcm_th3_l2_match_ctrl[unit]) {
    764         _bcm_th3_l2_match_ctrl[unit]->preserved = 0;
    765     }
    766 
    767     /*
    768      * Call chip-dependent initialization
    769      */
    770     BCM_IF_ERROR_RETURN(mbcm_driver[unit]->mbcm_l2_init(unit));
    771 
    772 #if defined(BCM_XGS_SWITCH_SUPPORT)
    773     /* Stop l2x thread if callback registration started it. */
    774     if (th3_l2_data[unit].flags & _BCM_TH3_L2X_THREAD_STOP) {
    775         BCM_IF_ERROR_RETURN(soc_l2x_stop(unit));
    776         /* Stop the learn thread */
    777         BCM_IF_ERROR_RETURN(soc_th3_l2_learn_thread_stop(unit));
    778     }
    779 #endif /* BCM_XGS_SWITCH_SUPPORT */
    780 
    781     /* Clear l2_data structure */
    782     th3_l2_data[unit].cb_count = 0;
    783     th3_l2_data[unit].flags = 0;
    784     sal_memset(&th3_l2_data[unit].cb, 0, sizeof(th3_l2_data[unit].cb));
    785 
    786     _th3_l2_init[unit] = 1; /* some positive value */
    787 
    788     return BCM_E_NONE;
    789 }
    790 
    791 /*
    792  * Function:
    793  *	bcm_tomahawk3_l2_key_dump
    794  * Purpose:
    795  *	Dump the key (VLAN+MAC) portion of a hardware-independent
    796  *	L2 address for debugging
    797  * Parameters:
    798  *	unit - Unit number
    799  *	pfx - String to print before output
    800  *	entry - Hardware-independent L2 entry to dump
    801  *	sfx - String to print after output
    802  */
    803 
    804 int
    805 bcm_tomahawk3_l2_key_dump(int unit, char *pfx, bcm_l2_addr_t *entry, char *sfx)
    806 {
    807     LOG_CLI((BSL_META_U(unit,
    808                         "l2: %sVLAN=0x%03x MAC=0x%02x%02x%02x"
    809              "%02x%02x%02x%s"), pfx, entry->vid,
    810              entry->mac[0], entry->mac[1], entry->mac[2],
    811              entry->mac[3], entry->mac[4], entry->mac[5], sfx));
    812 
    813     return BCM_E_NONE;
    814 }
    815 
    816 /*
    817  * Function:
    818  *	bcm_esw_l2_conflict_get
    819  * Purpose:
    820  *	Given an L2 address, return existing addresses which could conflict.
    821  * Parameters:
    822  *	unit		- switch device
    823  *	addr		- l2 address to search for conflicts
    824  *	cf_array	- (OUT) list of l2 addresses conflicting with addr
    825  *	cf_max		- number of entries allocated to cf_array
    826  *	cf_count	- (OUT) actual number of cf_array entries filled
    827  * Returns:
    828  *      BCM_E_XXX
    829  * Notes:
    830  *	Given an L2 or L2 multicast address, return any existing L2 or
    831  *	L2 multicast addresses which might prevent it from being
    832  *	inserted because a chip resource (like a hash bucket) is full.
    833  *	This routine could be used if bcm_l2_addr_add or bcm_l2_mcast_add
    834  *	returns BCM_E_FULL.
    835  */
    836 
    837 int
    838 bcm_tomahawk3_l2_conflict_get(int unit, bcm_l2_addr_t *addr,
    839                               bcm_l2_addr_t *cf_array, int cf_max,
    840                               int *cf_count)
    841 {
    842     TH3_L2_INIT(unit);
    843     /*
    844      * Call chip-dependent handler.
    845      */
    846     SOC_IF_ERROR_RETURN
    847        (mbcm_driver[unit]->mbcm_l2_conflict_get(unit, addr,
    848                                        cf_array, cf_max, cf_count));
    849 
    850     return BCM_E_NONE;
    851 }
    852 
    853 /*
    854  * Function:
    855  *     bcm_tomahawk3_l2_learn_limit_set
    856  * Description:
    857  *     Set the L2 MAC learning limit
    858  * Parameters:
    859  *     unit        device number
    860  *     limit       learn limit control info
    861  *                 limit->flags - qualifiers bits and action bits
    862  *                 limit->vlan - vlan identifier
    863  *                 limit->port - port number
    864  *                 limit->trunk - trunk identifier
    865  *                 limit->limit - max number of learned entry, -1 for unlimit
    866  * Return:
    867  *     BCM_E_XXX
    868  */
    869 int
    870 bcm_tomahawk3_l2_learn_limit_set(int unit, bcm_l2_learn_limit_t *limit)
    871 {
    872     return (BCM_E_UNAVAIL);
    873 }
    874 
    875 /*
    876  * Function:
    877  *     bcm_tomahawk3_l2_learn_limit_get
    878  * Description:
    879  *     Get the L2 MAC learning limit
    880  * Parameters:
    881  *     unit        device number
    882  *     limit       learn limit control info
    883  *                 limit->flags - qualifiers bits and action bits
    884  *                 limit->vlan - vlan identifier
    885  *                 limit->port - port number
    886  *                 limit->trunk - trunk identifier
    887  *                 limit->limit - max number of learned entry, -1 for unlimit
    888  * Return:
    889  *     BCM_E_XXX
    890  */
    891 int
    892 bcm_tomahawk3_l2_learn_limit_get(int unit, bcm_l2_learn_limit_t *limit)
    893 {
    894     return (BCM_E_UNAVAIL);
    895 }
    896 
    897 /*
    898  * Function:
    899  *     bcm_tomahawk3_l2_learn_class_set
    900  * Description:
    901  *     To set the attributes of L2 learning class
    902  * Parameters:
    903  *     unit        device number
    904  *     lclass      learning class id (0 - 3)
    905  *     lclass_prio learning class priority (0 - 3, 3 is the highest)
    906  *     flags       flags (BCM_L2_LEARN_CLASS_*)
    907  * Return:
    908  *     BCM_E_XXX
    909  * Note:
    910  *     This feature is disabled by default (see bcmPortControlLearnClassEnable).
    911  *     By default, each learning class is assigned priority 0 (lowest)
    912  *     and the attribute, BCM_L2_LEARN_CLASS_MOVE, is not set. By default,
    913  *     each port is assigned to learning class 0.
    914  */
    915 int
    916 bcm_tomahawk3_l2_learn_class_set(int unit, int lclass, int lclass_prio,
    917                                  uint32 flags)
    918 {
    919     return (BCM_E_UNAVAIL);
    920 }
    921 /*
    922  * Function:
    923  *     bcm_tomahawk3_l2_learn_class_get
    924  * Description:
    925  *     To get the attributes of L2 learning class
    926  * Parameters:
    927  *     unit        device number
    928  *     lclass      learning class id (0 - 3)
    929  *     lclass_prio learning class priority (0 - 3, 3 is the highest)
    930  *     flags       flags (BCM_L2_LEARN_CLASS_*)
    931  * Return:
    932  *     BCM_E_XXX
    933  */
    934 int
    935 bcm_tomahawk3_l2_learn_class_get(int unit, int lclass, int *lclass_prio,
    936                                  uint32 *flags)
    937 {
    938     return (BCM_E_UNAVAIL);
    939 }
    940 
    941 /*
    942  * Function:
    943  *     bcm_tomahawk3_l2_learn_stat_set
    944  * Description:
    945  *     To set or clear the specified L2 hash counter to the indicated value.
    946  * Parameters:
    947  *      unit - (IN) Unit number.
    948  *      learn_stat - (IN) Pointer to the L2 learned statistic structure.
    949  * Return:
    950  *     BCM_E_XXX
    951  * Note:
    952  *     The purposes of these counters are used to monitor the L2 hash condition.
    953  *     When the counter counts to 32'hffff_ffff (maximum value), it will keep this value till
    954  *     software clear it. Currently these L2 hash counters are system-wise.
    955  */
    956 int
    957 bcm_tomahawk3_l2_learn_stat_set(int unit, bcm_l2_learn_stat_t *learn_stat)
    958 {
    959     return (BCM_E_UNAVAIL);
    960 }
    961 
    962 /*
    963  * Function:
    964  *     bcm_tomahawk3_l2_learn_stat_get
    965  * Description:
    966  *     To get the statistic of the specified L2 hash counter from chip.
    967  * Parameters:
    968  *      unit - (IN) Unit number.
    969  *      learn_stat - (INOUT) Pointer to the L2 learned statistic structure.
    970  * Return:
    971  *     BCM_E_XXX
    972  * Note:
    973  *     The purposes of these counters are used to monitor the L2 hash condition.
    974  *     When the counter counts to 32'hffff_ffff (maximum value), it will keep this value till
    975  *     software clear it. Currently these L2 hash counters are system-wise.
    976  */
    977 int
    978 bcm_tomahawk3_l2_learn_stat_get(int unit, bcm_l2_learn_stat_t *learn_stat)
    979 {
    980     return (BCM_E_UNAVAIL);
    981 }
    982 
    983 /*
    984  * Function:
    985  *	_bcm_th3_delete_replace_flags_convert
    986  * Description:
    987  *	A helper function to all delete_by APIs to use bcm_l2_replace
    988  *  Converts L2 flags to L2 replace flags compatable to use with bcm_l2_replace
    989  * Parameters:
    990  *	unit        [IN]- device unit
    991  *	flags       [IN] - BCM_L2_DELETE_XXX
    992  *	repl_flags  [OUT]- Vflags BCM_L2_REPLACE_XXX
    993  * Returns:
    994  *	BCM_E_XXX
    995  */
    996 
    997 STATIC int
    998 _bcm_th3_delete_replace_flags_convert(int unit, uint32 flags,
    999                                       uint32 *repl_flags)
   1000 {
   1001     uint32 tmp_flags = BCM_L2_REPLACE_DELETE;
   1002 
   1003     /* Age feature only supported by bulk Control */
   1004     if (flags & BCM_L2_REPLACE_AGE){
   1005         return BCM_E_UNAVAIL;
   1006     }
   1007 
   1008     if (flags & BCM_L2_DELETE_PENDING) {
   1009         tmp_flags |= BCM_L2_REPLACE_PENDING;
   1010     }
   1011 
   1012     if (flags & BCM_L2_DELETE_STATIC) {
   1013         tmp_flags |= BCM_L2_REPLACE_MATCH_STATIC;
   1014     }
   1015 
   1016     if (flags & BCM_L2_DELETE_NO_CALLBACKS) {
   1017         tmp_flags |= BCM_L2_REPLACE_NO_CALLBACKS;
   1018     }
   1019 
   1020     *repl_flags = tmp_flags;
   1021 
   1022     return BCM_E_NONE;
   1023 }
   1024 
   1025 /*
   1026  * Function:
   1027  *      bcm_tomahawk3_l2_port_native
   1028  * Purpose:
   1029  *      Determine if the given port is "native" from the point
   1030  *      of view of L2.
   1031  * Parameters:
   1032  *      unit       - The unit
   1033  *      modid      - Module ID of L2 entry being queried
   1034  *      port       - Module port of L2 entry being queried
   1035  * Returns:
   1036  *      TRUE (> 0) if (modid, port) is front panel/CPU port for unit.
   1037  *      FALSE (0) otherwise.
   1038  *      < 0 on error.
   1039  *
   1040  *      Native means front panel, but also includes the CPU port.
   1041  *      HG ports are always excluded as are ports marked as internal or
   1042  *      external stacking
   1043  */
   1044 
   1045 int
   1046 bcm_tomahawk3_l2_port_native(int unit, int modid, int port)
   1047 {
   1048     bcm_trunk_t     tgid;
   1049     int             id;
   1050 
   1051     TH3_L2_INIT(unit);
   1052 
   1053     if (BCM_GPORT_IS_SET(port)) {
   1054         BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, port, &modid,
   1055             &port, &tgid, &id));
   1056 
   1057         if (-1 != id || BCM_TRUNK_INVALID != tgid) {
   1058             return FALSE;
   1059         }
   1060     }
   1061 
   1062     return TRUE;
   1063 }
   1064 
   1065 /*
   1066  * Function:
   1067  *     bcm_tomahawk3_l2_matched_traverse
   1068  * Description:
   1069  *     This function iterates over L2 table entries, find matching entries based
   1070  *     on criteria provided by the caller and executes user provided callback
   1071  *     function for each of the matching entries
   1072  * Parameters:
   1073  *      unit       - (IN) Unit number.
   1074  *      flags      - (IN) BCM_L2_TRAVERSE_* flags
   1075  *      match_addr - (IN) L2 address to match
   1076  *      trav_fn    - (IN) Callback function used for entries matching the
   1077  *                        address and the flags
   1078  *      user_data  - (IN) Pointer to data passed by caller, used with trav_fn
   1079  * Return:
   1080  *     BCM_E_XXX
   1081  * Note:
   1082  *     None
   1083  */
   1084 int
   1085 bcm_tomahawk3_l2_matched_traverse(int unit, uint32 flags,
   1086                                   bcm_l2_addr_t *match_addr,
   1087                                   bcm_l2_traverse_cb trav_fn, void *user_data)
   1088 {
   1089     uint32 replace_flags, int_flags;
   1090 
   1091     if (!trav_fn) {
   1092         return BCM_E_PARAM;
   1093     }
   1094 
   1095     if (!match_addr) {
   1096         return BCM_E_PARAM;
   1097     }
   1098 
   1099     replace_flags = 0;
   1100     int_flags = _BCM_L2_REPLACE_INT_NO_ACTION;
   1101     /*
   1102     * 1/ If BCM_L2_TRAVERSE_MATCH_DYNAMIC and BCM_L2_TRAVERSE_MATCH_STATIC 
   1103     *     are passed simultaneously to API bcm_l2_matched_traverse, 
   1104     *     this API will match all entries.
   1105     * 2/ If both BCM_L2_TRAVERSE_MATCH_DYNAMIC and BCM_L2_TRAVERSE_MATCH_STATIC 
   1106     *     are not passed to API bcm_l2_matched_traverse,
   1107     *     this API will also match all entries as before. This is the legacy behavior.
   1108     * 3/  If only BCM_L2_TRAVERSE_MATCH_DYNAMIC is passed to 
   1109     *     API bcm_l2_matched_traverse, this API will only match dynamic entries.
   1110     * 4/ If only BCM_L2_TRAVERSE_MATCH_STATIC is passed to 
   1111     *     API bcm_l2_matched_traverse, this API will only match static entries.  
   1112     */
   1113     if (((flags & BCM_L2_TRAVERSE_MATCH_STATIC) ? 1 : 0) ==
   1114         ((flags & BCM_L2_TRAVERSE_MATCH_DYNAMIC) ? 1 : 0)) {
   1115         /* Replace static as well as non-static entries */
   1116         replace_flags |= BCM_L2_REPLACE_MATCH_STATIC;
   1117     }
   1118     if (flags & BCM_L2_TRAVERSE_MATCH_MAC) {
   1119         replace_flags |= BCM_L2_REPLACE_MATCH_MAC;
   1120     }
   1121     if (flags & BCM_L2_TRAVERSE_MATCH_VLAN) {
   1122         replace_flags |= BCM_L2_REPLACE_MATCH_VLAN;
   1123     }
   1124     if (flags & BCM_L2_TRAVERSE_MATCH_DEST) {
   1125         replace_flags |= BCM_L2_REPLACE_MATCH_DEST;
   1126     }
   1127     if (!(flags & BCM_L2_TRAVERSE_IGNORE_DISCARD_SRC)) {
   1128         int_flags |= _BCM_L2_REPLACE_INT_MATCH_DISCARD_SRC;
   1129     }
   1130     if (!(flags & BCM_L2_TRAVERSE_IGNORE_DES_HIT)) {
   1131         int_flags |= _BCM_L2_REPLACE_INT_MATCH_DES_HIT;
   1132     }
   1133     if (!(flags & BCM_L2_TRAVERSE_IGNORE_SRC_HIT)) {
   1134         int_flags |= _BCM_L2_REPLACE_INT_MATCH_SRC_HIT;
   1135     }
   1136     if (flags & BCM_L2_TRAVERSE_MATCH_NATIVE) {
   1137         int_flags |= _BCM_L2_REPLACE_INT_MATCH_NATIVE;
   1138     }
   1139 
   1140     if ((flags & BCM_L2_TRAVERSE_MATCH_STATIC) &&
   1141          !(flags & BCM_L2_TRAVERSE_MATCH_DYNAMIC)){
   1142         int_flags |= _BCM_L2_REPLACE_INT_MATCH_ONLY_STATIC;
   1143     }
   1144 
   1145     return _bcm_th3_l2_replace(unit, replace_flags, int_flags, match_addr, 0,
   1146                                0, 0, trav_fn, user_data);
   1147 }
   1148 
   1149 /*
   1150  * Function:
   1151  *     _bcm_th3_l2_entry_valid
   1152  * Description:
   1153  *      Check if given L2 entry is valid
   1154  * Parameters:
   1155  *      unit         device number
   1156  *      mem         L2 memory to operate on
   1157  *      l2_entry    L2X entry read from HW
   1158  * Return:
   1159  *     BCM_E_NONE
   1160  *     BCM_E_NOT_FOUND
   1161  */
   1162 STATIC int
   1163 _bcm_th3_l2_entry_valid(int unit, soc_memacc_t *l2x_memacc, uint32 *l2_entry)
   1164 {
   1165     int valid;
   1166     int key_type;
   1167 
   1168     /* Value below can be read from l2_entry's BASE_VALID field (if reqd) */
   1169     valid = soc_memacc_field32_get(&l2x_memacc[_BCM_L2_MEMACC_VALID],
   1170                                            l2_entry);
   1171 
   1172     if (!valid) {
   1173         return BCM_E_NOT_FOUND;
   1174     }
   1175 
   1176     key_type = soc_memacc_field32_get(&l2x_memacc[_BCM_L2_MEMACC_KEY_TYPE],
   1177                                       l2_entry);
   1178 
   1179     if (key_type != TH3_L2_HASH_KEY_TYPE_BRIDGE) {
   1180         return BCM_E_NOT_FOUND;
   1181     }
   1182 
   1183     return BCM_E_NONE;
   1184 }
   1185 
   1186 /*
   1187  * Function:
   1188  *     _bcm_th3_l2_traverse_mem
   1189  * Description:
   1190  *      Helper function to _bcm_th3_l2_traverse to iterate over L2X memory 
   1191  *      and parse entries
   1192  * Parameters:
   1193  *     unit         device number
   1194  *     trav_st      Traverse structure with initialized data
   1195  * Return:
   1196  *     BCM_E_XXX
   1197  */
   1198 STATIC int
   1199 _bcm_th3_l2_traverse_mem(int unit, _bcm_l2_traverse_t *trav_st)
   1200 {
   1201     /* Indexes to iterate over memories, chunks and entries */
   1202     int             chnk_idx, ent_idx, chnk_idx_max, mem_idx_max;
   1203     int             buf_size, chunksize, chnk_end;
   1204     /* Buffer to store chunk of L2 table we currently work on */
   1205     uint32          *l2_tbl_chnk;
   1206     uint32          *l2_entry;
   1207     int             rv = BCM_E_NONE;
   1208     int             i;
   1209     soc_memacc_t    l2x_memacc_list[_BCM_L2_MEMACC_NUM];
   1210     soc_field_t     l2x_fields[_BCM_L2_MEMACC_NUM] = {
   1211         BASE_VALIDf,
   1212         KEY_TYPEf
   1213     };
   1214     _bcm_l2_replace_t *rep_st;
   1215     soc_mem_t mem = L2Xm;
   1216     
   1217     if (!soc_mem_index_count(unit, mem)) {
   1218         return BCM_E_NONE;
   1219     }
   1220 
   1221     for (i = 0; i < _BCM_L2_MEMACC_NUM; i++) {
   1222         rv = soc_memacc_init(unit, mem, l2x_fields[i], &l2x_memacc_list[i]);
   1223         if (BCM_FAILURE(rv)) {
   1224             SOC_MEMACC_INVALID_SET(&l2x_memacc_list[i]);
   1225         }
   1226     }
   1227 
   1228     chunksize = soc_property_get(unit, spn_L2DELETE_CHUNKS,
   1229                                  L2_MEM_CHUNKS_DEFAULT);
   1230 
   1231     buf_size = 4 * SOC_MAX_MEM_FIELD_WORDS * chunksize;
   1232     l2_tbl_chnk = soc_cm_salloc(unit, buf_size, "l2 traverse");
   1233     if (NULL == l2_tbl_chnk) {
   1234         return BCM_E_MEMORY;
   1235     }
   1236 
   1237     mem_idx_max = soc_mem_index_max(unit, mem);
   1238     for (chnk_idx = soc_mem_index_min(unit, mem); 
   1239          chnk_idx <= mem_idx_max; 
   1240          chnk_idx += chunksize) {
   1241         sal_memset((void *)l2_tbl_chnk, 0, buf_size);
   1242 
   1243         chnk_idx_max = 
   1244             ((chnk_idx + chunksize) < mem_idx_max) ? 
   1245             (chnk_idx + chunksize - 1) : mem_idx_max;
   1246 
   1247         rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY,
   1248                                 chnk_idx, chnk_idx_max, l2_tbl_chnk);
   1249         if (SOC_FAILURE(rv)) {
   1250             break;
   1251         }
   1252 
   1253         chnk_end = (chnk_idx_max - chnk_idx);
   1254         for (ent_idx = 0 ; ent_idx <= chnk_end; ent_idx ++) {
   1255             l2_entry = 
   1256                 soc_mem_table_idx_to_pointer(unit, mem, uint32 *, 
   1257                                              l2_tbl_chnk, ent_idx);
   1258             if (BCM_FAILURE(_bcm_th3_l2_entry_valid(unit, l2x_memacc_list,
   1259                                                     l2_entry))) {
   1260                 continue;
   1261             }
   1262 
   1263             trav_st->data = l2_entry;
   1264             trav_st->mem = mem;
   1265             trav_st->mem_idx = chnk_idx + ent_idx;
   1266             rv = trav_st->int_cb(unit, (void *)trav_st);
   1267             if (BCM_FAILURE(rv)) {
   1268                 break;
   1269             }
   1270         }
   1271         if (BCM_FAILURE(rv)) {
   1272             break;
   1273         }
   1274 
   1275         if (!trav_st->user_cb) {
   1276             /* Enhancement: use memory write range (per chunk) for replacing
   1277              * l2 entry data
   1278              */
   1279             rep_st = ((_bcm_l2_traverse_t *)trav_st)->user_data;
   1280             if (!(rep_st->flags & BCM_L2_REPLACE_DELETE)) {
   1281                 rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ANY,
   1282                                          chnk_idx, chnk_idx_max, l2_tbl_chnk);
   1283                 if (SOC_FAILURE(rv)) {
   1284                     break;
   1285                 }
   1286             }
   1287         }
   1288     }
   1289     soc_cm_sfree(unit, l2_tbl_chnk);
   1290     return rv;        
   1291 }
   1292 
   1293 /*
   1294  * Function:
   1295  *     _bcm_th3_l2_traverse
   1296  * Description:
   1297  *      Wrapper function for bcm_th3 to iterate over table and read L2X momery
   1298  * Parameters:
   1299  *     unit         Device number
   1300  *     trav_st      Traverse structure
   1301  * Return:
   1302  *     BCM_E_XXX
   1303  */
   1304 int 
   1305 _bcm_th3_l2_traverse(int unit, _bcm_l2_traverse_t *trav_st)
   1306 {
   1307     int rv = BCM_E_UNAVAIL; 
   1308 
   1309     rv = _bcm_th3_l2_traverse_mem(unit, trav_st);
   1310 
   1311     return rv;
   1312 }
   1313 
   1314 /*
   1315  * Function:
   1316  *     _bcm_th3_l2_traverse_int_cb
   1317  * Description:
   1318  *      Simple internal callback function for bcm_l2_traverse API to call
   1319  *      a user provided callback on a given entry.
   1320  * Parameters:
   1321  *      unit         device number
   1322  *      trav_st      traverse structure
   1323  * Return:
   1324  *     BCM_E_XXX
   1325  */
   1326 int
   1327 _bcm_th3_l2_traverse_int_cb(int unit, void *trav_st)
   1328 {
   1329     _bcm_l2_traverse_t *trv;
   1330     bcm_l2_addr_t      l2_addr; 
   1331 
   1332     trv = (_bcm_l2_traverse_t *)trav_st;
   1333 
   1334     BCM_IF_ERROR_RETURN(
   1335         _bcm_th3_l2_from_l2x(unit, &l2_addr, (l2x_entry_t *)(trv->data)));
   1336 
   1337     return trv->user_cb(unit, &l2_addr, trv->user_data);
   1338 }
   1339 
   1340 /*
   1341  * Function:
   1342  *     bcm_tomahawk3_l2_traverse
   1343  * Description:
   1344  *     Traverse L2 table and call provided callback function with matched entry
   1345  * Parameters:
   1346  *     unit         device number
   1347  *     trav_fn      User specified callback function 
   1348  *     user_data    User specified cookie
   1349  * Return:
   1350  *     BCM_E_XXX
   1351  */
   1352 int 
   1353 bcm_tomahawk3_l2_traverse(int unit, bcm_l2_traverse_cb trav_fn, void *user_data)
   1354 {
   1355     _bcm_l2_traverse_t  trav_st;
   1356     
   1357     TH3_L2_INIT(unit);
   1358 
   1359     if (!trav_fn) {
   1360         return (BCM_E_PARAM);
   1361     }
   1362 
   1363     sal_memset(&trav_st, 0, sizeof(_bcm_l2_traverse_t));
   1364     
   1365     trav_st.user_cb = trav_fn;
   1366     trav_st.user_data = user_data;
   1367     trav_st.int_cb = _bcm_th3_l2_traverse_int_cb;
   1368 
   1369     return (_bcm_th3_l2_traverse(unit, &trav_st));
   1370 }
   1371 
   1372 /*
   1373  * Function:
   1374  *     _bcm_th3_l2_replace_dest_setup
   1375  * Description:
   1376  *     Helper function to bcm_l2_replace API to setup a destination
   1377   * Parameters:
   1378  *      unit     - (IN) Unit number.
   1379  *      module   - (IN) Module number
   1380  *      port     - (IN) Port number for matching L2 entry
   1381  *      trunk    - (IN) Trunkid for matching L2 entry. Valid if is_trunk is TRUE
   1382  *      is_trunk - (IN) To specify if 'trunk' is valid
   1383  * Return:
   1384  *     BCM_E_XXX
   1385  * Note:
   1386  * This function is called replace APIs, and indirectly, by delete_by APIs
   1387  */
   1388 STATIC int
   1389 _bcm_th3_l2_replace_dest_setup(int unit, bcm_module_t module, bcm_port_t port,
   1390                                bcm_trunk_t trunk, int is_trunk,
   1391                                _bcm_l2_replace_dest_t *dest)
   1392 {
   1393     /* If all are -1, means ignore the replacement with new destination */
   1394     if (port == -1 && trunk == -1) {
   1395         dest->module = dest->port = dest->trunk = dest->vp = -1;
   1396         return BCM_E_NONE;
   1397     }
   1398 
   1399     if (BCM_GPORT_IS_SET(port)) {
   1400 
   1401         
   1402         BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, port, &dest->module,
   1403                                                    &dest->port, &dest->trunk,
   1404                                                    &dest->vp));
   1405     } else if (is_trunk) {
   1406         
   1407         BCM_IF_ERROR_RETURN(_bcm_trunk_id_validate(unit, trunk));
   1408 
   1409         dest->trunk = trunk;
   1410         dest->vp = -1;
   1411     } else {
   1412         /* Check to maintain backward compatibility for
   1413          *  replace/traverse/delete_by APIs
   1414          */
   1415         if (!SOC_MODID_ADDRESSABLE(unit, module)) {
   1416             return BCM_E_BADID;
   1417         }
   1418         dest->module =  0; /* Not used */
   1419 
   1420         if (!SOC_PORT_ADDRESSABLE(unit, port)) {
   1421             return BCM_E_PORT;
   1422         }
   1423         dest->port = port;
   1424         dest->trunk = -1;
   1425         dest->vp = -1;
   1426     }
   1427 
   1428     return BCM_E_NONE;
   1429 }
   1430 
   1431 STATIC int
   1432 _bcm_th3_l2_replace_data_mask_setup(int unit, _bcm_l2_replace_t *rep)
   1433 {
   1434     bcm_mac_t mac_mask;
   1435     bcm_mac_t mac_data;
   1436     int field_len;
   1437 
   1438     sal_memset(&rep->match_mask, 0, sizeof(l2x_entry_t));
   1439     sal_memset(&rep->match_data, 0, sizeof(l2x_entry_t));
   1440     sal_memset(&rep->new_mask, 0, sizeof(l2x_entry_t));
   1441     sal_memset(&rep->new_data, 0, sizeof(l2x_entry_t));
   1442 
   1443     soc_mem_field32_set(unit, L2Xm, &rep->match_mask, BASE_VALIDf, 1);
   1444     soc_mem_field32_set(unit, L2Xm, &rep->match_data, BASE_VALIDf, 1);
   1445 
   1446     if (rep->key_type != -1) {
   1447         field_len = soc_mem_field_length(unit, L2Xm, KEY_TYPEf);
   1448         soc_mem_field32_set(unit, L2Xm, &rep->match_mask, KEY_TYPEf,
   1449                             (1 << field_len) - 1);
   1450         soc_mem_field32_set(unit, L2Xm, &rep->match_data, KEY_TYPEf,
   1451                             rep->key_type);
   1452     }
   1453 
   1454     if (rep->flags & BCM_L2_REPLACE_MATCH_VLAN) {
   1455         soc_mem_field32_set(unit, L2Xm, &rep->match_mask, VLAN_IDf, 0xfff);
   1456         soc_mem_field32_set(unit, L2Xm, &rep->match_data, VLAN_IDf,
   1457                             rep->key_vlan);
   1458     }
   1459 
   1460     if (rep->flags & BCM_L2_REPLACE_MATCH_MAC) {
   1461         sal_memset(&mac_mask, 0xFF, sizeof(mac_mask));
   1462         soc_mem_mac_addr_set(unit, L2Xm, &rep->match_mask, MAC_ADDRf,
   1463                              mac_mask);
   1464         soc_mem_mac_addr_set(unit, L2Xm, &rep->match_data, MAC_ADDRf,
   1465                              rep->key_mac);
   1466     }
   1467 
   1468     if ((rep->flags & BCM_L2_REPLACE_MATCH_UC) &&
   1469         !(rep->flags & BCM_L2_REPLACE_MATCH_MC)) {
   1470         /* The 40th bit of Unicast must be 0 */
   1471         sal_memset(&mac_mask, 0x00, sizeof(mac_mask));
   1472         mac_mask[0] = 0x01;
   1473         sal_memset(&mac_data, 0x00, sizeof(mac_data));
   1474         soc_mem_mac_addr_set(unit, L2Xm, &rep->match_mask, MAC_ADDRf,
   1475                              mac_mask);
   1476         soc_mem_mac_addr_set(unit, L2Xm, &rep->match_data, MAC_ADDRf,
   1477                              mac_data);
   1478     } else if ((rep->flags & BCM_L2_REPLACE_MATCH_MC) &&
   1479         !(rep->flags & BCM_L2_REPLACE_MATCH_UC)) {
   1480         /* The 40th bit of Multicast must be 1 */
   1481         sal_memset(&mac_mask, 0x00, sizeof(mac_mask));
   1482         mac_mask[0] = 0x01;
   1483         sal_memset(&mac_data, 0x00, sizeof(mac_data));
   1484         mac_data[0] = 0x01;
   1485         soc_mem_mac_addr_set(unit, L2Xm, &rep->match_mask, MAC_ADDRf,
   1486                              mac_mask);
   1487         soc_mem_mac_addr_set(unit, L2Xm, &rep->match_data, MAC_ADDRf,
   1488                              mac_data);
   1489     }
   1490 
   1491     if (rep->flags & BCM_L2_REPLACE_MATCH_DEST) {
   1492         field_len = soc_mem_field_length(unit, L2Xm, DEST_TYPEf);
   1493         soc_mem_field32_set(unit, L2Xm, &rep->match_mask, DEST_TYPEf,
   1494                             (1 << field_len) - 1);
   1495 
   1496         if (rep->match_dest.trunk != -1) {
   1497             soc_mem_field32_set(unit, L2Xm, &rep->match_data,
   1498                                 DEST_TYPEf, 1);
   1499 
   1500             field_len = soc_mem_field_length(unit, L2Xm, TGIDf);
   1501             soc_mem_field32_set(unit, L2Xm, &rep->match_mask, TGIDf,
   1502                                 (1 << field_len) - 1);
   1503             soc_mem_field32_set(unit, L2Xm, &rep->match_data, TGIDf,
   1504                                 rep->match_dest.trunk);
   1505         } else {
   1506             /* DEST_TYPE field in data is 0 */
   1507 
   1508             if (rep->match_dest.port != -1) {
   1509                 field_len = soc_mem_field_length(unit, L2Xm, PORT_NUMf);
   1510                 soc_mem_field32_set(unit, L2Xm, &rep->match_mask,
   1511                                     PORT_NUMf, (1 << field_len) - 1);
   1512                 soc_mem_field32_set(unit, L2Xm, &rep->match_data,
   1513                                     PORT_NUMf, rep->match_dest.port);
   1514             }
   1515 
   1516             
   1517         }
   1518     }
   1519 
   1520     /* BCM_L2_REPLACE_MATCH_STATIC means to replace static as well as
   1521      * non-static entries
   1522      */
   1523     if (!(rep->flags & BCM_L2_REPLACE_MATCH_STATIC)) {
   1524         if (rep->int_flags & _BCM_L2_REPLACE_INT_MATCH_ONLY_STATIC) {
   1525             soc_mem_field32_set(unit, L2Xm, &rep->match_mask, STATIC_BITf, 1);
   1526             soc_mem_field32_set(unit, L2Xm, &rep->match_data, STATIC_BITf, 1);
   1527         } else { 
   1528             soc_mem_field32_set(unit, L2Xm, &rep->match_mask, STATIC_BITf, 1);
   1529             /* STATIC_BIT field in data is 0 */
   1530         }
   1531     }
   1532     /* STATIC_BIT field in mask is 0 */
   1533 
   1534     if (rep->int_flags & _BCM_L2_REPLACE_INT_MATCH_DISCARD_SRC) {
   1535         soc_mem_field32_set(unit, L2Xm, &rep->match_mask, SRC_DISCARDf, 1);
   1536         if (rep->key_l2_flags & BCM_L2_DISCARD_SRC) {
   1537             soc_mem_field32_set(unit, L2Xm, &rep->match_data, SRC_DISCARDf, 1);
   1538         }
   1539     }
   1540 
   1541     if (rep->int_flags & _BCM_L2_REPLACE_INT_MATCH_SRC_HIT) {
   1542         soc_mem_field32_set(unit, L2Xm, &rep->match_mask, HITSAf, 1);
   1543         if (rep->key_l2_flags & BCM_L2_SRC_HIT) {
   1544             soc_mem_field32_set(unit, L2Xm, &rep->match_data, HITSAf, 1);
   1545         }
   1546     }
   1547     if (rep->int_flags & _BCM_L2_REPLACE_INT_MATCH_DES_HIT) {
   1548         soc_mem_field32_set(unit, L2Xm, &rep->match_mask, HITDAf, 1);
   1549         if (rep->key_l2_flags & BCM_L2_DES_HIT) {
   1550             soc_mem_field32_set(unit, L2Xm, &rep->match_data, HITDAf, 1);
   1551         }
   1552     }
   1553 
   1554     if (rep->int_flags & _BCM_L2_REPLACE_INT_MATCH_NATIVE) {
   1555         soc_mem_field32_set(unit, L2Xm, &rep->match_mask, LOCAL_SAf, 1);
   1556         if (rep->key_l2_flags & BCM_L2_NATIVE) {
   1557             soc_mem_field32_set(unit, L2Xm, &rep->match_data, LOCAL_SAf, 1);
   1558         }
   1559     }
   1560 
   1561     if (_CLEAR_ALL_ENTRIES_SRC_OR_DES_HIT_BIT(rep->flags)) {
   1562         if (rep->flags & BCM_L2_REPLACE_DES_HIT_CLEAR) {
   1563             soc_mem_field32_set(unit, L2Xm, &rep->match_mask, HITDAf, 1);
   1564             soc_mem_field32_set(unit, L2Xm, &rep->match_data, HITDAf, 1);
   1565         }
   1566         if (rep->flags & BCM_L2_REPLACE_SRC_HIT_CLEAR) {
   1567             soc_mem_field32_set(unit, L2Xm, &rep->match_mask, HITSAf, 1);
   1568             soc_mem_field32_set(unit, L2Xm, &rep->match_data, HITSAf, 1);
   1569         }
   1570     }
   1571 
   1572     if (!(rep->flags & BCM_L2_REPLACE_DELETE)) {
   1573         if (!_CLEAR_ALL_ENTRIES_SRC_OR_DES_HIT_BIT(rep->flags)) {
   1574             if (rep->new_dest.trunk != -1) {
   1575                 field_len = soc_mem_field_length(unit, L2Xm, DEST_TYPEf);
   1576                 soc_mem_field32_set(unit, L2Xm, &rep->new_mask, DEST_TYPEf,
   1577                                     (1 << field_len) - 1);
   1578 
   1579                 soc_mem_field32_set(unit, L2Xm, &rep->new_data, DEST_TYPEf, 1);
   1580 
   1581                 /*
   1582                  * Writing to DESTINATION field instead of TGIDf
   1583                  * to ensure the MSB bits of DESTINATION are cleared.
   1584                  */
   1585                 field_len = soc_mem_field_length(unit, L2Xm, DESTINATIONf);
   1586                 soc_mem_field32_set(unit, L2Xm, &rep->new_mask,
   1587                                     DESTINATIONf, (1 << field_len) - 1);
   1588                 soc_mem_field32_set(unit, L2Xm, &rep->new_data,
   1589                                     DESTINATIONf, rep->new_dest.trunk);
   1590             } else if (rep->new_dest.port != -1 && rep->new_dest.module != -1) {
   1591                     /* DEST_TYPE field in data is 0 */
   1592                     field_len = soc_mem_field_length(unit, L2Xm, DEST_TYPEf);
   1593                     soc_mem_field32_set(unit, L2Xm, &rep->new_mask, DEST_TYPEf,
   1594                                         (1 << field_len) - 1);
   1595 
   1596                     field_len = soc_mem_field_length(unit, L2Xm, PORT_NUMf);
   1597                     soc_mem_field32_set(unit, L2Xm, &rep->new_mask,
   1598                                         PORT_NUMf, (1 << field_len) - 1);
   1599                     soc_mem_field32_set(unit, L2Xm, &rep->new_data,
   1600                                         PORT_NUMf, rep->new_dest.port);
   1601             }
   1602         }
   1603 
   1604         if (rep->flags & BCM_L2_REPLACE_DES_HIT_CLEAR) {
   1605             soc_mem_field32_set(unit, L2Xm, &rep->new_mask, HITDAf, 1);
   1606         }
   1607         if (rep->flags & BCM_L2_REPLACE_SRC_HIT_CLEAR) {
   1608             soc_mem_field32_set(unit, L2Xm, &rep->new_mask, HITSAf, 1);
   1609         }
   1610     }
   1611 
   1612     return BCM_E_NONE;
   1613 }
   1614 
   1615 STATIC int
   1616 _bcm_th3_l2_is_soc_l2_mem_cache_enabled(int unit)
   1617 {
   1618     soc_mem_t mem = L2Xm;
   1619     uint32 *cache;
   1620     int copyno = SOC_MEM_BLOCK_ANY(unit, mem);
   1621 
   1622     cache = SOC_MEM_STATE(unit, mem).cache[copyno];
   1623 
   1624     if (cache == NULL) {
   1625         return FALSE;
   1626     }
   1627 
   1628     return TRUE;
   1629 }
   1630 
   1631 /*
   1632  * Function:
   1633  *     _bcm_th3_l2_entry_replace
   1634  * Description:
   1635  *     Helper function to bcm_l2_replace API to be used as a call back for
   1636  *     bcm_l2_traverse API and replace given entry if MAC matches
   1637  * Parameters:
   1638  *     unit         device number
   1639  *     trav_st      structure with information from traverse function
   1640  * Return:
   1641  *     BCM_E_XXX
   1642  */
   1643 STATIC int
   1644 _bcm_th3_l2_entry_replace(int unit, void *trav_st)
   1645 {
   1646     _bcm_l2_replace_t *rep_st;
   1647     soc_mem_t   mem;
   1648     uint32      *entry;
   1649     uint32      *match_data, *match_mask;
   1650     int         entry_words, i, idx, rv;
   1651     bcm_mac_t   l2mac;
   1652     int         port_val, trunk_val;
   1653     soc_control_t   *soc = SOC_CONTROL(unit);
   1654     bcm_l2_addr_t l2_addr; 
   1655 
   1656     if (trav_st == NULL) {
   1657         return BCM_E_PARAM;
   1658     }
   1659 
   1660     mem = ((_bcm_l2_traverse_t *)trav_st)->mem;
   1661     entry = ((_bcm_l2_traverse_t *)trav_st)->data;
   1662     idx = ((_bcm_l2_traverse_t *)trav_st)->mem_idx;
   1663     rep_st = ((_bcm_l2_traverse_t *)trav_st)->user_data;
   1664 
   1665     if (rep_st == NULL || entry == NULL || mem == INVALIDm) {
   1666         return BCM_E_PARAM;
   1667     }
   1668 
   1669     match_data = (uint32 *)&rep_st->match_data;
   1670     match_mask = (uint32 *)&rep_st->match_mask;
   1671     entry_words = soc_mem_entry_words(unit, mem);
   1672 
   1673     for (i = 0; i < entry_words; i++) {
   1674         if ((entry[i] ^ match_data[i]) & match_mask[i]) {
   1675             return BCM_E_NONE;
   1676         }
   1677     }
   1678     if (rep_st->int_flags & _BCM_L2_REPLACE_INT_NO_ACTION) {
   1679         BCM_IF_ERROR_RETURN
   1680             (_bcm_th3_l2_from_l2x(unit, &l2_addr, (l2x_entry_t *)entry));
   1681         return rep_st->trav_fn(unit, &l2_addr, rep_st->user_data);
   1682     }
   1683     if (rep_st->flags & BCM_L2_REPLACE_DELETE) {
   1684         MEM_LOCK(unit, mem);
   1685         if (SOC_L2_DEL_SYNC_LOCK(soc) < 0) {
   1686             MEM_UNLOCK(unit, mem);
   1687             return BCM_E_RESOURCE;
   1688         }
   1689         rv = soc_mem_delete(unit, mem, MEM_BLOCK_ALL, entry);
   1690 #ifdef BCM_XGS_SWITCH_SUPPORT
   1691         if (BCM_SUCCESS(rv)) {
   1692             rv = soc_l2x_sync_delete(unit, entry, idx,
   1693                      rep_st->flags & BCM_L2_REPLACE_NO_CALLBACKS ?
   1694                      SOC_L2X_NO_CALLBACKS : 0);
   1695 
   1696             if (rep_st->flags & BCM_L2_REPLACE_NO_CALLBACKS) {
   1697                 sal_mutex_take(SOC_CONTROL(unit)->l2x_lrn_shadow_mutex,
   1698                                sal_mutex_FOREVER);
   1699                 soc_th3_lrn_shadow_delete(unit, (l2x_entry_t *)entry);
   1700                 sal_mutex_give(SOC_CONTROL(unit)->l2x_lrn_shadow_mutex);
   1701             }
   1702         }
   1703 #endif /* BCM_XGS_SWITCH_SUPPORT */
   1704         SOC_L2_DEL_SYNC_UNLOCK(soc);
   1705         MEM_UNLOCK(unit, mem);
   1706 
   1707         return rv;
   1708     }
   1709 
   1710     if (rep_st->flags & BCM_L2_REPLACE_MATCH_VLAN) {
   1711         if (soc_mem_field32_get(unit, mem, entry, VLAN_IDf) !=
   1712                 rep_st->key_vlan) {
   1713                 return BCM_E_NONE;
   1714         }
   1715     }
   1716 
   1717     if (rep_st->flags & BCM_L2_REPLACE_MATCH_MAC) {
   1718         soc_mem_mac_addr_get(unit, mem, entry, MAC_ADDRf, l2mac);
   1719         if (ENET_CMP_MACADDR(rep_st->key_mac, l2mac)) {
   1720             return BCM_E_NONE;
   1721         }
   1722     }
   1723 
   1724     if (rep_st->flags & BCM_L2_REPLACE_MATCH_DEST) {
   1725         trunk_val = -1;
   1726         port_val = -1;
   1727 
   1728         if (soc_mem_field32_get(unit, mem, entry, Tf)) {
   1729             trunk_val = soc_mem_field32_get(unit, mem, entry, TGIDf);
   1730         } else {
   1731             port_val = soc_mem_field32_get(unit, mem, entry, PORT_NUMf);
   1732         }
   1733 
   1734         if (rep_st->match_dest.trunk != -1) {
   1735             if (rep_st->match_dest.trunk != trunk_val) {
   1736                 return BCM_E_NONE;
   1737             }
   1738         } else {
   1739             if (rep_st->match_dest.port != port_val) {
   1740                 return BCM_E_NONE;
   1741             }
   1742         }
   1743     }
   1744 
   1745     /* Check if user wants static field matched with the entry's static bit */
   1746     if (!(rep_st->flags & BCM_L2_REPLACE_MATCH_STATIC)) {
   1747         /* BCM_L2_REPLACE_MATCH_STATIC means to replace static as well as
   1748          * non-static entries */
   1749         if (soc_mem_field32_get(unit, mem, entry, STATIC_BITf)) {
   1750             return BCM_E_NONE;
   1751         }
   1752     }
   1753 
   1754     /* Perform replace action on matching entry */
   1755     /* Note: replace delete flag has been handled at top of this function */
   1756     if (rep_st->new_dest.trunk != -1) { /* New destination is trunk */
   1757         soc_mem_field32_set(unit, mem, entry, DEST_TYPEf, 1);
   1758         soc_mem_field32_set(unit, mem, entry, TGIDf,
   1759                             rep_st->new_dest.trunk);
   1760     } else { /* New destination is mod port */
   1761         soc_mem_field32_set(unit, mem, entry, DEST_TYPEf, 0);
   1762         soc_mem_field32_set(unit, mem, entry, PORT_NUMf,
   1763                             rep_st->new_dest.port);
   1764     }
   1765 
   1766     return soc_mem_write(unit, mem, MEM_BLOCK_ALL, idx, entry);
   1767 }
   1768 
   1769 /*
   1770  * Function:
   1771  *     _bcm_th3_l2_replace
   1772  * Description:
   1773  *     Helper function called by main replace API implementation
   1774  * Parameters:
   1775  *      unit - (IN) Unit number.
   1776  *      flags - (IN) BCM_L2_REPLACE_* flags
   1777  *      match_addr - (IN) L2 information used to match one/more L2 addresses
   1778  *      new_module - (IN) Module number. Not used, see Note below 
   1779  *      new_port   - (IN) Port number to replace in the matching entries
   1780  *      new_trunk  - (IN) Port number to replace in the matching entries
   1781  *      trav_fn    - (IN) Callback function (optional) to process matchin
   1782  *                        entries
   1783  *      user_data  - (IN) Arguments to pass to callback function (trav_fn)
   1784  *                        (optional)
   1785  * Return:
   1786  *     BCM_E_XXX
   1787  * Note:
   1788  * new_module is not used. We accept it here for maintaining compatibility of
   1789  * various APIs' behavior. Invalid module id will be rejected inside the call
   1790  * sequence below
   1791  */
   1792 STATIC int
   1793 _bcm_th3_l2_replace(int unit, uint32 flags, uint32 int_flags,
   1794                     bcm_l2_addr_t *match_addr, bcm_module_t new_module,
   1795                     bcm_port_t new_port, bcm_trunk_t new_trunk,
   1796                     bcm_l2_traverse_cb trav_fn,
   1797                     void *user_data)
   1798 {
   1799     _bcm_l2_replace_t   rep_st;
   1800     _bcm_l2_traverse_t  trav_st;
   1801     int                 rv = BCM_E_UNAVAIL;
   1802     int                 do_freeze;
   1803 
   1804     sal_memset(&rep_st, 0, sizeof(_bcm_l2_replace_t));
   1805     sal_memset(&trav_st, 0, sizeof(_bcm_l2_traverse_t));
   1806 
   1807     rep_st.trav_fn = trav_fn;
   1808     rep_st.user_data = user_data;
   1809     rep_st.flags = flags;
   1810     rep_st.int_flags = int_flags;
   1811     if ((int_flags & _BCM_L2_REPLACE_IGNORE_PORTID) &&
   1812         !(flags & BCM_L2_REPLACE_DELETE) &&
   1813         !(flags & BCM_L2_REPLACE_MATCH_DEST)) {
   1814         return BCM_E_PARAM;
   1815     }
   1816 
   1817     if (!(flags & BCM_L2_REPLACE_DELETE) &&
   1818         !(int_flags & _BCM_L2_REPLACE_INT_NO_ACTION)) {
   1819         BCM_IF_ERROR_RETURN(_bcm_th3_l2_replace_dest_setup
   1820                             (unit, new_module, new_port, new_trunk,
   1821                              flags & BCM_L2_REPLACE_NEW_TRUNK,
   1822                              &rep_st.new_dest));
   1823     }
   1824 
   1825     /* Note rep_st.key_type is 0 */
   1826 
   1827     if (match_addr != NULL) {
   1828         rep_st.key_l2_flags = match_addr->flags;
   1829 
   1830         if (flags & BCM_L2_REPLACE_MATCH_DEST) {
   1831             if (int_flags & _BCM_L2_REPLACE_IGNORE_PORTID) {
   1832                 if (!SOC_MODID_ADDRESSABLE(unit, match_addr->modid)) {
   1833                     return BCM_E_BADID;
   1834                 }
   1835                 rep_st.match_dest.vp = -1;
   1836                 rep_st.match_dest.trunk = -1;
   1837                 rep_st.match_dest.port = -1;
   1838                 rep_st.match_dest.module = 0; /* match_addr->modid; ignored */
   1839             } else {
   1840                 BCM_IF_ERROR_RETURN(_bcm_th3_l2_replace_dest_setup
   1841                                     (unit, match_addr->modid, match_addr->port,
   1842                                      match_addr->tgid,
   1843                                      match_addr->flags & BCM_L2_TRUNK_MEMBER,
   1844                                      &rep_st.match_dest));
   1845             }
   1846         }
   1847 
   1848         if (flags & BCM_L2_REPLACE_MATCH_VLAN) {
   1849             rep_st.key_vfi = -1;
   1850             VLAN_CHK_ID(unit, match_addr->vid);
   1851             rep_st.key_vlan = match_addr->vid;
   1852             rep_st.key_type = 0;  /* L2 Bridge */
   1853         }
   1854 
   1855         if (flags & BCM_L2_REPLACE_MATCH_MAC) {
   1856             sal_memcpy(&rep_st.key_mac, match_addr->mac, sizeof(bcm_mac_t));
   1857             /* When replace L2 by MAC, key type must be provided. */
   1858             /* Key type is 0 by default for L2 Bridge. */
   1859         }
   1860     }
   1861 
   1862     BCM_IF_ERROR_RETURN(_bcm_th3_l2_replace_data_mask_setup(unit, &rep_st));
   1863 
   1864     /* Delete operation don't require freeze */
   1865     do_freeze = FALSE;
   1866     if (!(flags & BCM_L2_REPLACE_DELETE) ||
   1867         ((flags & BCM_L2_REPLACE_MATCH_STATIC) &&
   1868           _bcm_th3_l2_is_soc_l2_mem_cache_enabled(unit))) {
   1869         do_freeze = TRUE;
   1870     }
   1871 
   1872     if (do_freeze) {
   1873         BCM_IF_ERROR_RETURN(bcm_esw_l2_addr_freeze(unit));
   1874     }
   1875 
   1876     trav_st.user_data = (void *)&rep_st;
   1877     trav_st.int_cb = _bcm_th3_l2_entry_replace;
   1878     rv = _bcm_th3_l2_traverse(unit, &trav_st);
   1879 
   1880     /* Check with Michael what this does    rv = _soc_l2_sync_mem_cache(unit, &rep_st); */
   1881 
   1882     if (do_freeze) {
   1883         BCM_IF_ERROR_RETURN(bcm_esw_l2_addr_thaw(unit));
   1884     }
   1885 
   1886     return rv;
   1887 }
   1888 
   1889 /*
   1890  * Function:
   1891  *	bcm_tomahawk3_l2_addr_delete_by_mac
   1892  * Description:
   1893  *	Delete L2 entries associated with a MAC address
   1894  * Parameters:
   1895  *	unit  - device unit
   1896  *	mac   - MAC address
   1897  *	flags - BCM_L2_DELETE_XXX
   1898  * Returns:
   1899  *	BCM_E_XXX
   1900  * Notes:
   1901  *	Static entries are removed only if BCM_L2_DELETE_STATIC flag is used.
   1902  *	L2 aging and learning are disabled during this operation
   1903  */
   1904 int
   1905 bcm_tomahawk3_l2_addr_delete_by_mac(int unit, bcm_mac_t mac, uint32 flags)
   1906 {
   1907     bcm_l2_addr_t   match_addr;
   1908     uint32          repl_flags;
   1909 
   1910     TH3_L2_INIT(unit);
   1911 
   1912     sal_memset(&match_addr, 0, sizeof(bcm_l2_addr_t));
   1913     sal_memcpy(match_addr.mac, mac, sizeof(bcm_mac_t));
   1914 
   1915     BCM_IF_ERROR_RETURN
   1916         (_bcm_th3_delete_replace_flags_convert(unit, flags, &repl_flags));
   1917 
   1918     /* Traverse l2 entry contains MAC address field by key type */
   1919     repl_flags |= BCM_L2_REPLACE_MATCH_MAC;
   1920 
   1921     return _bcm_th3_l2_replace(unit, repl_flags, 0, &match_addr, 0, 0, 0,
   1922                                NULL, NULL);
   1923 }
   1924 
   1925 /*
   1926  * Function:
   1927  *	bcm_tomahawk3_l2_addr_delete_by_vlan
   1928  * Description:
   1929  *	Delete L2 entries associated with a VLAN
   1930  * Parameters:
   1931  *	unit  - device unit
   1932  *	vid   - VLAN id
   1933  *	flags - BCM_L2_DELETE_XXX
   1934  * Returns:
   1935  *	BCM_E_XXX
   1936  * Notes:
   1937  *	Static entries are removed only if BCM_L2_DELETE_STATIC flag is used
   1938  *	L2 aging and learning are disabled during this operation.
   1939  */
   1940 int
   1941 bcm_tomahawk3_l2_addr_delete_by_vlan(int unit, bcm_vlan_t vid, uint32 flags)
   1942 {
   1943     bcm_l2_addr_t   match_addr;
   1944     uint32          repl_flags;
   1945 
   1946     TH3_L2_INIT(unit);
   1947 
   1948     sal_memset(&match_addr, 0, sizeof(bcm_l2_addr_t));
   1949     match_addr.vid = vid;
   1950     BCM_IF_ERROR_RETURN
   1951         (_bcm_th3_delete_replace_flags_convert(unit, flags, &repl_flags));
   1952     repl_flags |= BCM_L2_REPLACE_MATCH_VLAN;
   1953     return _bcm_th3_l2_replace(unit, repl_flags, 0, &match_addr, 0, 0, 0,
   1954                                NULL, NULL);
   1955 }
   1956 
   1957 /*
   1958  * Function:
   1959  *	bcm_tomahawk3_l2_addr_delete_by_port
   1960  * Description:
   1961  *	Delete L2 addresses associated with a destination module/port.
   1962  * Parameters:
   1963  *	unit  - device unit
   1964  *	mod   - module id (or -1 for local unit)
   1965  *	port  - port
   1966  *	flags - BCM_L2_DELETE_XXX
   1967  * Returns:
   1968  *	BCM_E_XXX
   1969  * Notes:
   1970  *	Static entries are removed only if BCM_L2_DELETE_STATIC flag is used.
   1971  *	L2 aging and learning are disabled during this operation.
   1972  */
   1973 
   1974 int
   1975 bcm_tomahawk3_l2_addr_delete_by_port(int unit,
   1976                                      bcm_module_t mod, bcm_port_t port,
   1977                                      uint32 flags)
   1978 {
   1979     bcm_l2_addr_t   match_addr;
   1980     uint32          repl_flags;
   1981     uint32          int_flags = 0;
   1982 
   1983     TH3_L2_INIT(unit);
   1984 
   1985     sal_memset(&match_addr, 0, sizeof(bcm_l2_addr_t));
   1986     if (port == -1) {
   1987         /* non zero mod id is not used, replace will return error */
   1988         match_addr.modid = mod;
   1989         match_addr.port  = -1;
   1990         int_flags = _BCM_L2_REPLACE_IGNORE_PORTID;
   1991     } else if (!BCM_GPORT_IS_SET(port) && mod == -1) {
   1992         if (!SOC_PORT_VALID(unit, port)) {
   1993             return BCM_E_PORT;
   1994         }
   1995 
   1996         match_addr.modid = SOC_BASE_MODID(unit);
   1997     } else {
   1998         match_addr.modid = mod;
   1999     }
   2000 
   2001     match_addr.port = port;
   2002 
   2003     BCM_IF_ERROR_RETURN
   2004         (_bcm_th3_delete_replace_flags_convert(unit, flags, &repl_flags));
   2005 
   2006     repl_flags |= BCM_L2_REPLACE_MATCH_DEST;
   2007 
   2008     return _bcm_th3_l2_replace(unit, repl_flags, int_flags, &match_addr, 0, 0,
   2009                                0, NULL, NULL);
   2010 }
   2011 
   2012 /*
   2013  * Function:
   2014  *	bcm_tomahawk3_l2_addr_delete_by_trunk
   2015  * Description:
   2016  *	Delete L2 entries associated with a trunk
   2017  * Parameters:
   2018  *	unit  - device unit
   2019  *	tid   - trunk id
   2020  *	flags - BCM_L2_DELETE_XXX
   2021  * Returns:
   2022  *	BCM_E_XXX
   2023  * Notes:
   2024  *	Static entries are removed only if BCM_L2_DELETE_STATIC flag is used
   2025  *	L2 aging and learning are disabled during this operation.
   2026  */
   2027 int
   2028 bcm_tomahawk3_l2_addr_delete_by_trunk(int unit, bcm_trunk_t tid, uint32 flags)
   2029 {
   2030     bcm_l2_addr_t   match_addr;
   2031     uint32          repl_flags;
   2032 
   2033     TH3_L2_INIT(unit);
   2034 
   2035     sal_memset(&match_addr, 0, sizeof(bcm_l2_addr_t));
   2036     match_addr.tgid = tid;
   2037     match_addr.flags = BCM_L2_TRUNK_MEMBER;
   2038 
   2039     BCM_IF_ERROR_RETURN
   2040         (_bcm_th3_delete_replace_flags_convert(unit, flags, &repl_flags));
   2041     repl_flags |= BCM_L2_REPLACE_MATCH_DEST;
   2042 
   2043     return _bcm_th3_l2_replace(unit, repl_flags, 0, &match_addr, 0, 0, 0,
   2044                                NULL, NULL);
   2045 }
   2046 
   2047 /*
   2048  * Function:
   2049  *	bcm_tomahawk3_l2_addr_delete_by_mac_port
   2050  * Description:
   2051  *	Delete L2 entries associated with a MAC address and
   2052  *	a destination module/port
   2053  * Parameters:
   2054  *	unit  - device unit
   2055  *	mac   - MAC address
   2056  *	mod   - module id
   2057  *	port  - port
   2058  *	flags - BCM_L2_DELETE_XXX
   2059  * Returns:
   2060  *	BCM_E_XXX
   2061  * Notes:
   2062  *	Static entries are removed only if BCM_L2_DELETE_STATIC flag is used.
   2063  *	L2 aging and learning are disabled during this operation.
   2064  */
   2065 int
   2066 bcm_tomahawk3_l2_addr_delete_by_mac_port(int unit, bcm_mac_t mac,
   2067                                          bcm_module_t mod, bcm_port_t port,
   2068                                          uint32 flags)
   2069 {
   2070     bcm_l2_addr_t   match_addr;
   2071     uint32          repl_flags;
   2072 
   2073     TH3_L2_INIT(unit);
   2074 
   2075     sal_memset(&match_addr, 0, sizeof(bcm_l2_addr_t));
   2076     sal_memcpy(match_addr.mac, mac, sizeof(bcm_mac_t));
   2077 
   2078     if (!BCM_GPORT_IS_SET(port) && mod == -1) {
   2079         if (!SOC_PORT_VALID(unit, port)) {
   2080             return BCM_E_PORT;
   2081         }
   2082         match_addr.modid = SOC_BASE_MODID(unit);
   2083     } else {
   2084         match_addr.modid = mod;
   2085     }
   2086     match_addr.port = port;
   2087     BCM_IF_ERROR_RETURN
   2088         (_bcm_th3_delete_replace_flags_convert(unit, flags, &repl_flags));
   2089     repl_flags |= BCM_L2_REPLACE_MATCH_MAC | BCM_L2_REPLACE_MATCH_DEST;
   2090     return _bcm_th3_l2_replace(unit, repl_flags, 0, &match_addr, 0, 0, 0,
   2091                                NULL, NULL);
   2092 }
   2093 
   2094 /*
   2095  * Function:
   2096  *	bcm_tomahawk3_l2_addr_delete_by_vlan_port
   2097  * Description:
   2098  *	Delete L2 entries associated with a VLAN and
   2099  *	a destination module/port
   2100  * Parameters:
   2101  *	unit  - device unit
   2102  *	vid   - VLAN id
   2103  *	mod   - module id
   2104  *	port  - port
   2105  *	flags - BCM_L2_DELETE_XXX
   2106  * Returns:
   2107  *	BCM_E_XXX
   2108  * Notes:
   2109  *	Static entries are removed only if BCM_L2_DELETE_STATIC flag is used.
   2110  *	L2 aging and learning are disabled during this operation.
   2111  */
   2112 int
   2113 bcm_tomahawk3_l2_addr_delete_by_vlan_port(int unit, bcm_vlan_t vid,
   2114                                           bcm_module_t mod, bcm_port_t port,
   2115                                           uint32 flags)
   2116 {
   2117     bcm_l2_addr_t   match_addr;
   2118     uint32          repl_flags;
   2119 
   2120     TH3_L2_INIT(unit);
   2121 
   2122     sal_memset(&match_addr, 0, sizeof(bcm_l2_addr_t));
   2123     match_addr.vid = vid;
   2124 
   2125     if (!BCM_GPORT_IS_SET(port) && mod == -1) {
   2126         if (!SOC_PORT_VALID(unit, port)) {
   2127             return BCM_E_PORT;
   2128         }
   2129         match_addr.modid = SOC_BASE_MODID(unit);
   2130     } else {
   2131         match_addr.modid = mod;
   2132     }
   2133     match_addr.port = port;
   2134     BCM_IF_ERROR_RETURN
   2135         (_bcm_th3_delete_replace_flags_convert(unit, flags, &repl_flags));
   2136     repl_flags |= BCM_L2_REPLACE_MATCH_VLAN | BCM_L2_REPLACE_MATCH_DEST;
   2137     return _bcm_th3_l2_replace(unit, repl_flags, 0, &match_addr, 0, 0, 0,
   2138                                NULL, NULL);
   2139 }
   2140 
   2141 /*
   2142  * Function:
   2143  *	bcm_tomahawk3_l2_addr_delete_by_vlan_trunk
   2144  * Description:
   2145  *	Delete L2 entries associated with a VLAN and a
   2146  *      destination trunk.
   2147  * Parameters:
   2148  *	unit  - device unit
   2149  *	vid   - VLAN id
   2150  *	tid   - trunk group id
   2151  *	flags - BCM_L2_DELETE_XXX
   2152  * Returns:
   2153  *	BCM_E_XXX
   2154  * Notes:
   2155  *	Static entries are removed only if BCM_L2_DELETE_STATIC flag is used.
   2156  *	L2 aging and learning are disabled during this operation.
   2157  */
   2158 int
   2159 bcm_tomahawk3_l2_addr_delete_by_vlan_trunk(int unit, bcm_vlan_t vid,
   2160                                            bcm_trunk_t tid, uint32 flags)
   2161 {
   2162     bcm_l2_addr_t   match_addr;
   2163     uint32          repl_flags;
   2164 
   2165     TH3_L2_INIT(unit);
   2166 
   2167     sal_memset(&match_addr, 0, sizeof(bcm_l2_addr_t));
   2168     match_addr.vid = vid;
   2169     match_addr.tgid = tid;
   2170     match_addr.flags = BCM_L2_TRUNK_MEMBER;
   2171 
   2172     BCM_IF_ERROR_RETURN
   2173         (_bcm_th3_delete_replace_flags_convert(unit, flags, &repl_flags));
   2174     repl_flags |= BCM_L2_REPLACE_MATCH_VLAN | BCM_L2_REPLACE_MATCH_DEST;
   2175     return _bcm_th3_l2_replace(unit, repl_flags, 0, &match_addr, 0, 0, 0,
   2176                                NULL, NULL);
   2177 }
   2178 
   2179 /*
   2180  * Function:
   2181  *     bcm_tomahawk3_l2_replace
   2182  * Description:
   2183  *     This function replaces, or deletes destination for multiple L2 entries
   2184  * Parameters:
   2185  *     unit         device number
   2186  *     flags        flags BCM_L2_REPLACE_*
   2187  *     match_addr   L2 parameters to match on delete/replace
   2188  *     new_module   new module ID for a replace (not used)
   2189  *     new_port     new port for a replace
   2190  *     new_trunk    new trunk for a replace
   2191  * Return:
   2192  *     BCM_E_XXX
   2193  * Notes:
   2194  * The following replace flags are supported on Tomahawk3 since there are no
   2195  * requirements in this area (refer PRD), and/or there is no h/w support for
   2196  * these flags (Example, flags related to VPN, pending flag and so on)
   2197  */
   2198 int
   2199 bcm_tomahawk3_l2_replace(int unit, uint32 flags, bcm_l2_addr_t *match_addr,
   2200                          bcm_module_t new_module, bcm_port_t new_port,
   2201                          bcm_trunk_t new_trunk)
   2202 {
   2203     TH3_L2_INIT(unit);
   2204 
   2205     if (!flags) {
   2206         return BCM_E_PARAM;
   2207     }
   2208 
   2209     if ((flags & (BCM_L2_REPLACE_DELETE | BCM_L2_REPLACE_AGE)) &&
   2210         (flags & BCM_L2_REPLACE_NEW_TRUNK)) {
   2211         return BCM_E_PARAM;
   2212     }
   2213 
   2214     /* The following flags are not supported */
   2215     if ((flags & BCM_L2_REPLACE_VPN_TYPE) ||
   2216         (flags & BCM_L2_REPLACE_VLAN_AND_VPN_TYPE) ||
   2217         (flags & BCM_L2_REPLACE_PENDING) ||
   2218         (flags & BCM_L2_REPLACE_IGNORE_PENDING) ||
   2219         (flags & BCM_L2_REPLACE_LEARN_LIMIT) ||
   2220         (flags & BCM_L2_REPLACE_AGE)) {
   2221         return BCM_E_UNAVAIL;
   2222     }
   2223 
   2224     if ((flags & BCM_L2_REPLACE_DELETE) && (flags & BCM_L2_REPLACE_MATCH_MAC) &&
   2225         ((flags & BCM_L2_REPLACE_MATCH_UC) ||
   2226          (flags & BCM_L2_REPLACE_MATCH_MC))) {
   2227         return BCM_E_PARAM;
   2228     }
   2229 
   2230     /* matching L2 address allowed to be NULL together with */
   2231     /* BCM_L2_REPLACE_DELETE flag indicating to delete all entries */
   2232     if (NULL == match_addr) {
   2233         if (!(flags & BCM_L2_REPLACE_DELETE) &&
   2234             !(flags & (BCM_L2_REPLACE_SRC_HIT_CLEAR |
   2235                        BCM_L2_REPLACE_DES_HIT_CLEAR))) {
   2236             return BCM_E_PARAM;
   2237         }
   2238         flags &= ~(BCM_L2_REPLACE_MATCH_VLAN | BCM_L2_REPLACE_MATCH_MAC |
   2239                    BCM_L2_REPLACE_MATCH_DEST);
   2240     }
   2241     /* coverity[var_deref_op : FALSE] */
   2242     /* coverity[var_deref_model : FALSE] */
   2243     return _bcm_th3_l2_replace(unit, flags, 0, match_addr, new_module,
   2244                                      new_port, new_trunk, NULL, NULL);
   2245 }
   2246 
   2247 
   2248 #if 0
   2249 #ifdef BCM_XGS_SWITCH_SUPPORT
   2250 /*
   2251  * Function:
   2252  *     _bcm_get_op_from_flags
   2253  * Description:
   2254  *     Helper function to _bcm_fb_age_reg_config to 
   2255  *     decide on a PPA command according to flags
   2256  * Parameters:
   2257  *     flags        flags BCM_L2_REPLACE_* 
   2258  *     op           PPA command to be programmed
   2259  *     sync_op      Search Key for _soc_l2x_sync_delete_by
   2260  * Return:
   2261  *     BCM_E_NONE   - Success
   2262  *     BCM_E_PARAM  - Failure
   2263  */
   2264 int 
   2265 _bcm_get_op_from_flags(uint32 flags, uint32 *op, uint32 *sync_op)
   2266 {
   2267     uint32 cmp_flags = 0, int_op = 0, int_sync_op = 0;
   2268     int    rv = BCM_E_NONE;
   2269 
   2270     if (NULL == op) {
   2271         return BCM_E_PARAM;
   2272     }
   2273     cmp_flags = flags & (BCM_L2_REPLACE_MATCH_VLAN |
   2274                          BCM_L2_REPLACE_MATCH_DEST);
   2275     switch (cmp_flags) {
   2276         case BCM_L2_REPLACE_MATCH_VLAN: 
   2277         {
   2278             int_op = (flags & BCM_L2_REPLACE_DELETE ? XGS_PPAMODE_VLAN : 
   2279                    XGS_PPAMODE_VLAN_REPLACE);
   2280             int_sync_op = (flags & BCM_L2_REPLACE_DELETE ? SOC_L2X_VLAN_DEL : 
   2281                            SOC_L2X_NO_DEL);
   2282          break;
   2283         }
   2284         case BCM_L2_REPLACE_MATCH_DEST :
   2285         {
   2286             int_op = (flags & BCM_L2_REPLACE_DELETE ? XGS_PPAMODE_PORTMOD :
   2287                    XGS_PPAMODE_PORTMOD_REPLACE);
   2288             int_sync_op = (flags & BCM_L2_REPLACE_DELETE ? SOC_L2X_PORTMOD_DEL : 
   2289                            SOC_L2X_NO_DEL);
   2290             break;
   2291         }
   2292         case BCM_L2_REPLACE_MATCH_VLAN | BCM_L2_REPLACE_MATCH_DEST:
   2293         {
   2294             int_op = (flags & BCM_L2_REPLACE_DELETE ? XGS_PPAMODE_PORTMOD_VLAN :
   2295                    XGS_PPAMODE_PORTMOD_VLAN_REPLACE);
   2296             int_sync_op = (flags & BCM_L2_REPLACE_DELETE ? SOC_L2X_PORTMOD_VLAN_DEL : 
   2297                            SOC_L2X_NO_DEL);
   2298 
   2299             break;
   2300         }
   2301         default:
   2302             rv = BCM_E_PARAM;
   2303             break;
   2304     }
   2305 
   2306     *op = int_op;
   2307     *sync_op = int_sync_op;
   2308     return rv;
   2309 }
   2310 
   2311 #endif /* BCM_XGS_SWITCH_SUPPORT */
   2312 
   2313 STATIC int
   2314 _soc_l2_sync_mem_cache(int unit, _bcm_l2_replace_t *rep_st)
   2315 {
   2316     uint8 *vmap;
   2317     soc_mem_t mem = L2Xm;
   2318     uint32 *cache, *entry, *match_data, *match_mask;
   2319     uint32 *new_data, *new_mask;
   2320     int index_max, idx, i;
   2321     int entry_dw = soc_mem_entry_words(unit, mem);
   2322     int entry_words = soc_mem_entry_words(unit, mem);
   2323     int copyno = SOC_MEM_BLOCK_ANY(unit, mem);
   2324     soc_field_t vld_fld = VALIDf;
   2325 
   2326     cache = SOC_MEM_STATE(unit, mem).cache[copyno];
   2327     if (cache == NULL) {
   2328         return BCM_E_NONE;
   2329     }
   2330 
   2331     if (soc_feature(unit, soc_feature_base_valid)) {
   2332         vld_fld = BASE_VALIDf;
   2333     }
   2334     vmap = SOC_MEM_STATE(unit, mem).vmap[copyno];
   2335     index_max = soc_mem_index_max(unit, mem);
   2336     for (idx = 0; idx <= index_max; idx++) {
   2337         if (!CACHE_VMAP_TST(vmap, idx)) {
   2338             continue;
   2339         }
   2340         entry = cache + (idx * entry_dw);
   2341         if (!soc_mem_field32_get(unit, mem, entry, vld_fld)) {
   2342             continue;
   2343         }
   2344         if (!soc_mem_field32_get(unit, mem, entry, STATIC_BITf)) {
   2345             continue;
   2346         }
   2347         match_data = (uint32 *)&rep_st->match_data;
   2348         match_mask = (uint32 *)&rep_st->match_mask;
   2349         for (i = 0; i < entry_words; i++) {
   2350             if ((entry[i] ^ match_data[i]) & match_mask[i]) {
   2351                 break;
   2352             }
   2353         }
   2354         if (i != entry_words) {
   2355             continue;
   2356         }
   2357         /* Match found, delete or replace entry */
   2358         LOG_VERBOSE(BSL_LS_SOC_COMMON,
   2359                     (BSL_META_U(unit,
   2360                                 "Match found in L2 bulk cache op: %d\n"), idx));
   2361         if (rep_st->flags & BCM_L2_REPLACE_DELETE) {
   2362             /* Delete op - invalidate the entry */
   2363             CACHE_VMAP_CLR(vmap, idx);
   2364         } else {
   2365             /* Replace op - update entry */
   2366             new_data = (uint32 *)&rep_st->new_data;
   2367             new_mask = (uint32 *)&rep_st->new_mask;
   2368             for (i = 0; i < entry_words; i++) {
   2369                 entry[i] ^= (entry[i] ^ new_data[i]) & new_mask[i];
   2370             }
   2371         }
   2372     }
   2373     return BCM_E_NONE;
   2374 }
   2375 
   2376 /*
   2377  * Function:
   2378  *     bcm_esw_l2_station_add
   2379  * Description:
   2380  *     Add an entry to L2 Station Table      
   2381  * Parameters:
   2382  *     unit         - (IN) BCM device number
   2383  *     station_id   - (IN/OUT) Station ID
   2384  *     station      - (IN) Pointer to station address information
   2385  * Return:
   2386  *     BCM_E_XXX
   2387  */
   2388 int
   2389 bcm_esw_l2_station_add(int unit, int *station_id, bcm_l2_station_t *station)
   2390 {
   2391     int rv = BCM_E_UNAVAIL;
   2392 
   2393 #if defined(BCM_TRIUMPH_SUPPORT)
   2394     if (SOC_IS_TRIDENT(unit) || SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWK(unit)
   2395         || SOC_IS_KATANAX(unit) || SOC_IS_TRIUMPH3(unit) || SOC_IS_TRIDENT3(unit)) {
   2396         rv = bcm_tr_l2_station_add(unit, station_id, station);
   2397     }
   2398 #endif
   2399 
   2400     return (rv);
   2401 }
   2402 
   2403 /*
   2404  * Function:
   2405  *     bcm_esw_l2_station_delete
   2406  * Description:
   2407  *     Delete an entry from L2 Station Table
   2408  * Parameters:
   2409  *     unit         - (IN) BCM device number
   2410  *     station_id   - (IN) Station ID
   2411  * Return:
   2412  *     BCM_E_XXX
   2413  */
   2414 int
   2415 bcm_esw_l2_station_delete(int unit, int station_id)
   2416 {
   2417 
   2418     int rv = BCM_E_UNAVAIL;
   2419 
   2420 #if defined(BCM_TRIUMPH_SUPPORT)
   2421     if (SOC_IS_TRIDENT(unit) || SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWK(unit)
   2422         || SOC_IS_KATANAX(unit) || SOC_IS_TRIUMPH3(unit) || SOC_IS_TRIDENT3(unit)) {
   2423         rv = bcm_tr_l2_station_delete(unit, station_id);
   2424     }
   2425 #endif
   2426     return (rv);
   2427 }
   2428 
   2429 /*
   2430  * Function:
   2431  *     bcm_esw_l2_station_delete_all
   2432  * Description:
   2433  *     Clear all L2 Station Table entries
   2434  * Parameters:
   2435  *     unit - (IN) BCM device number
   2436  * Return:
   2437  *     BCM_E_XXX
   2438  */
   2439 int
   2440 bcm_esw_l2_station_delete_all(int unit)
   2441 {
   2442     int rv = BCM_E_UNAVAIL;
   2443 
   2444 #if defined(BCM_TRIUMPH_SUPPORT)
   2445     if (SOC_IS_TRIDENT(unit) || SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWK(unit)
   2446         || SOC_IS_KATANAX(unit) || SOC_IS_TRIUMPH3(unit) || SOC_IS_TRIDENT3(unit)) {
   2447         rv = bcm_tr_l2_station_delete_all(unit);
   2448     }
   2449 #endif
   2450 
   2451     return (rv);
   2452 }
   2453 
   2454 /*
   2455  * Function:
   2456  *     bcm_esw_l2_station_get
   2457  * Description:
   2458  *     Get L2 station entry detail from Station Table
   2459  * Parameters:
   2460  *     unit         - (IN) BCM device number
   2461  *     station_id   - (IN) Station ID
   2462  *     station      - (OUT) Pointer to station address information.
   2463  * Return:
   2464  *     BCM_E_XXX
   2465  */
   2466 int
   2467 bcm_esw_l2_station_get(int unit, int station_id, bcm_l2_station_t *station)
   2468 {
   2469     int rv = BCM_E_UNAVAIL;
   2470 
   2471 #if defined(BCM_TRIUMPH_SUPPORT)
   2472     if (SOC_IS_TRIDENT(unit) || SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWK(unit)
   2473         || SOC_IS_KATANAX(unit) || SOC_IS_TRIUMPH3(unit) || SOC_IS_TRIDENT3(unit)) {
   2474         rv = bcm_tr_l2_station_get(unit, station_id, station);
   2475     }
   2476 #endif
   2477 
   2478     return (rv);
   2479 }
   2480 
   2481 /*
   2482  * Function:
   2483  *     bcm_esw_l2_station_size_get
   2484  * Description:
   2485  *     Get size of L2 Station Table
   2486  * Parameters:
   2487  *     unit - (IN) BCM device number
   2488  *     size - (OUT) L2 Station table size
   2489  * Return:
   2490  *     BCM_E_XXX
   2491  */
   2492 int
   2493 bcm_esw_l2_station_size_get(int unit, int *size)
   2494 {
   2495     int rv = BCM_E_UNAVAIL;
   2496 
   2497 #if defined(BCM_TRIUMPH_SUPPORT)
   2498     if (SOC_IS_TRIDENT(unit) || SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWK(unit)
   2499         || SOC_IS_KATANAX(unit) || SOC_IS_TRIUMPH3(unit) || SOC_IS_TRIDENT3(unit)) {
   2500         rv = bcm_tr_l2_station_size_get(unit, size);
   2501     }
   2502 #endif
   2503 
   2504     return (rv);
   2505 }
   2506 
   2507 /*
   2508  * Function:
   2509  *     bcm_esw_l2_station_traverse
   2510  * Description:
   2511  *     Traverse L2 station entry from Station Table
   2512  * Parameters:
   2513  *     unit         - (IN) BCM device number
   2514  *     trav_fn   -  (IN) Customer defines function is used to traverse
   2515  *     user_data - (IN) Pointer to information of customer.
   2516  * Return:
   2517  *     BCM_E_XXX
   2518  */
   2519 int 
   2520 bcm_esw_l2_station_traverse(int unit, bcm_l2_station_traverse_cb trav_fn, void *user_data)
   2521 {
   2522     int rv = BCM_E_UNAVAIL;
   2523 
   2524 #if defined(BCM_TRIUMPH_SUPPORT)
   2525     if (SOC_IS_TRIDENT(unit) || SOC_IS_TRIDENT2X(unit) ||
   2526         SOC_IS_TOMAHAWK(unit) || SOC_IS_KATANAX(unit) ||
   2527         SOC_IS_TRIUMPH3(unit) || SOC_IS_TRIDENT3(unit)) {
   2528         rv = bcm_tr_l2_station_traverse(unit, trav_fn, user_data);
   2529     }
   2530 #endif
   2531 
   2532     return (rv);
   2533 }
   2534 
   2535 #endif
   2536 
   2537 int
   2538 bcm_tomahawk3_l2_ring_replace( int unit, bcm_l2_ring_t *l2_ring)
   2539 {
   2540     return BCM_E_UNAVAIL;
   2541 }
   2542 
   2543 /*
   2544  * Function:
   2545  *     bcm_tomahawk3_l2_mac_port_create
   2546  * Description:
   2547  *     Create a MAC port.
   2548  * Parameters:
   2549  *     unit - (IN) BCM device number
   2550  *     mac_port - (IN/OUT) MAC port info
   2551  * Return:
   2552  *     BCM_E_XXX
   2553  */
   2554 int
   2555 bcm_tomahawk3_l2_mac_port_create(int unit, bcm_l2_mac_port_t *mac_port)
   2556 {
   2557     return BCM_E_UNAVAIL;
   2558 }
   2559 
   2560 /*
   2561  * Function:
   2562  *     bcm_tomahawk3_l2_mac_port_destroy
   2563  * Description:
   2564  *     Destroy a MAC port.
   2565  * Parameters:
   2566  *     unit - (IN) BCM device number
   2567  *     mac_port_id - (IN) MAC port GPORT ID
   2568  * Return:
   2569  *     BCM_E_XXX
   2570  */
   2571 int
   2572 bcm_tomahawk3_l2_mac_port_destroy(int unit, bcm_gport_t mac_port_id)
   2573 {
   2574     return BCM_E_UNAVAIL;
   2575 }
   2576 
   2577 /*
   2578  * Function:
   2579  *     bcm_tomahawk3_l2_mac_port_destroy_all
   2580  * Description:
   2581  *     Destroy all MAC ports.
   2582  * Parameters:
   2583  *     unit - (IN) BCM device number
   2584  * Return:
   2585  *     BCM_E_XXX
   2586  */
   2587 int
   2588 bcm_tomahawk3_l2_mac_port_destroy_all(int unit)
   2589 {
   2590     return BCM_E_UNAVAIL;
   2591 }
   2592 
   2593 /*
   2594  * Function:
   2595  *     bcm_tomahawk3_l2_mac_port_get
   2596  * Description:
   2597  *     Get info about a MAC port.
   2598  * Parameters:
   2599  *     unit - (IN) BCM device number
   2600  *     mac_port - (IN/OUT) MAC port info
   2601  * Return:
   2602  *     BCM_E_XXX
   2603  */
   2604 int
   2605 bcm_tomahawk3_l2_mac_port_get(int unit, bcm_l2_mac_port_t *mac_port)
   2606 {
   2607     return BCM_E_UNAVAIL;
   2608 }
   2609 
   2610 /*
   2611  * Function:
   2612  *     bcm_tomahawk3_l2_mac_port_traverse
   2613  * Description:
   2614  *     Traverse MAC ports.
   2615  * Parameters:
   2616  *     unit - (IN) BCM device number
   2617  *     cb   - (IN) Callback
   2618  *     user_data - (IN) User data
   2619  * Return:
   2620  *     BCM_E_XXX
   2621  */
   2622 int
   2623 bcm_tomahawk3_l2_mac_port_traverse(int unit, bcm_l2_mac_port_traverse_cb cb,
   2624         void *user_data)
   2625 {
   2626     return BCM_E_UNAVAIL;
   2627 }
   2628 
   2629 STATIC void
   2630 _bcm_th3_l2_vlan_gport_free(int unit, _bcm_l2_del_vlan_port_pair_t *l2_pair)
   2631 {
   2632     int i;
   2633     
   2634     if (l2_pair) {
   2635         if (l2_pair->mod_pair_arr) {
   2636             sal_free(l2_pair->mod_pair_arr);
   2637             l2_pair->mod_pair_arr = NULL;
   2638         } 
   2639 
   2640         if (l2_pair->unit_pair_arr) {
   2641             for (i = 0; i < BCM_VLAN_MAX + 2; i++) {
   2642                 sal_free(l2_pair->unit_pair_arr->tbm[i]);
   2643                 l2_pair->unit_pair_arr->tbm[i] = NULL;
   2644             }
   2645             sal_free(l2_pair->unit_pair_arr);
   2646             l2_pair->unit_pair_arr = NULL;
   2647         }
   2648     }
   2649 
   2650     return;
   2651 }
   2652 
   2653 #if defined(INCLUDE_L3)
   2654 /*
   2655  * Function:
   2656  *     _bcm_th3_is_gport_valid_type
   2657  * Purpose:
   2658  *     Returns TRUE if supplied gport is a valid VP type
   2659  * Parameters:
   2660  *     gport_type    -  (IN) Gport type to be validated
   2661  * Returns:
   2662  *     TRUE if 'gport' is a valid VP type, FALSE otherwise
   2663  */
   2664 
   2665 STATIC int
   2666 _bcm_th3_is_gport_valid_type(int gport_type)
   2667 {
   2668     switch(gport_type) {
   2669         case BCM_GPORT_MPLS_PORT:
   2670         case BCM_GPORT_VLAN_PORT:
   2671             return 1;
   2672         default:
   2673             return 0;
   2674     }
   2675 }
   2676 #endif /* INCLUDE_L3 */
   2677 
   2678 /*
   2679  * Function:
   2680  *     _bcm_th3_l2_vlan_gport_matched_delete
   2681  * Purpose:
   2682  *     L2 Traverse callback function to Purge L2 entry belongs
   2683  *     to set of (vlan,port) tuple.
   2684  * Parameters:
   2685  *     unit       -  (IN) Device unit number
   2686  *     info       -  (IN) Reference to L2 entry, delete on match
   2687  *     user_data  -  (IN) User specified cookie
   2688  * Returns:
   2689  *     BCM_E_XXX
   2690  * Note:
   2691  *     If one of the elements of the (vlan,gport) pair is invalid
   2692  *     (if vlan value is BCM_VLAN_INVALID or port value is BCM_GPORT_INVALID),
   2693  *     it is a wildcard. 
   2694  */
   2695 STATIC int
   2696 _bcm_th3_l2_vlan_gport_matched_delete(int unit, bcm_l2_addr_t *info,
   2697                                       void *user_data)
   2698 {
   2699     int                            rv = BCM_E_NONE;
   2700     int                            entry_found = FALSE;
   2701     _bcm_l2_del_vlan_port_pair_t  *l2_pair;
   2702     int                            useGport;
   2703 #if defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3)
   2704     int                            gport_type;
   2705     bcm_port_t                     local_port;
   2706 #endif /* defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3) */
   2707 
   2708     l2_pair = (void *)user_data;
   2709 
   2710     if (l2_pair == NULL) {
   2711         return BCM_E_NOT_FOUND;
   2712     }
   2713 
   2714     if ((info->flags & BCM_L2_STATIC) &&  
   2715         (!(l2_pair->replace_flags & BCM_L2_REPLACE_MATCH_STATIC))) {
   2716         _l2_dbg_unmatched_entries[unit]++;  
   2717         return BCM_E_NONE;
   2718     }
   2719 
   2720     if ((info->flags & BCM_L2_PENDING) &&  
   2721         (!(l2_pair->replace_flags & BCM_L2_REPLACE_PENDING))) {
   2722         _l2_dbg_unmatched_entries[unit]++;
   2723         return BCM_E_NONE;
   2724     }
   2725 
   2726     /* Assumption is that esw's version of switch control will be used on TH3 */
   2727     BCM_IF_ERROR_RETURN
   2728         (bcm_esw_switch_control_get(unit, bcmSwitchUseGport, &useGport));
   2729 
   2730 #if defined(INCLUDE_L3)
   2731     /* Extract the gport_type */
   2732     gport_type = (((info->port) >> _SHR_GPORT_TYPE_SHIFT) & _SHR_GPORT_TYPE_MASK);
   2733     if (_bcm_th3_is_gport_valid_type(gport_type)) {
   2734         /* Assumption is that esw's version of switch control will be used on
   2735          * TH3
   2736          */
   2737         BCM_IF_ERROR_RETURN(
   2738             bcm_esw_port_local_get(unit, info->port, &local_port));
   2739     }
   2740 #endif /* defined(INCLUDE_L3) */
   2741 
   2742     if (BCM_VLAN_VEC_GET(l2_pair->del_by_vlan_vec, info->vid)) {
   2743         /* Delete by vlan operation */
   2744         entry_found = TRUE;
   2745     } else if ((useGport) && (BCM_GPORT_IS_MODPORT(info->port)) &&
   2746                BCM_PBMP_MEMBER (l2_pair->mod_pair_arr[info->modid].pbm[BCM_VLAN_MAX+1],
   2747                                 _SHR_GPORT_LOCAL_GET(info->port))) {
   2748         /* Delete by (mod, gport) operation */
   2749         entry_found = TRUE;
   2750     } else if ((!useGport) && (!BCM_GPORT_IS_SET(info->port)) &&
   2751                BCM_PBMP_MEMBER (l2_pair->mod_pair_arr[info->modid].pbm[BCM_VLAN_MAX+1],
   2752                                 info->port)) {
   2753         /* Delete by (mod, port) operation */
   2754         entry_found = TRUE;
   2755     } else if ((useGport) && BCM_GPORT_IS_MODPORT(info->port) &&
   2756                BCM_PBMP_MEMBER(l2_pair->mod_pair_arr[info->modid].pbm[info->vid],
   2757                 _SHR_GPORT_LOCAL_GET(info->port))) {
   2758         /* Delete by (vlan, (mod, gport)) operation */
   2759         entry_found = TRUE;
   2760     } else if (((!useGport) && (!BCM_GPORT_IS_SET(info->port)) &&
   2761                 BCM_PBMP_MEMBER(l2_pair->mod_pair_arr[info->modid].pbm[info->vid],
   2762                 info->port))) {
   2763         /* Delete by (vlan, (mod, port)) operation */
   2764         entry_found = TRUE;
   2765     } else if (info->flags & BCM_L2_TRUNK_MEMBER) {
   2766         if (SHR_BITGET(l2_pair->unit_pair_arr[0].tbm[BCM_VLAN_MAX+1], info->tgid)) {
   2767             /* Delete by (tid) operation */
   2768             entry_found = TRUE;
   2769         } else if (SHR_BITGET(l2_pair->unit_pair_arr[0].tbm[info->vid], info->tgid)) {
   2770             /* Delete by (vlan, tid) operation */
   2771             entry_found = TRUE;
   2772         }
   2773     }
   2774 
   2775     if (entry_found == TRUE) {
   2776        /* Entry found - Delete the entry */
   2777 
   2778        rv = mbcm_driver[unit]->mbcm_l2_addr_delete(unit, info->mac,
   2779                                                    info->vid);
   2780        if (rv == BCM_E_NONE) {
   2781            _l2_dbg_matched_entries[unit]++;
   2782        }
   2783    } else {
   2784        _l2_dbg_unmatched_entries[unit]++;
   2785    }
   2786 
   2787    return rv;
   2788 }
   2789 
   2790 /*
   2791  * Function:
   2792  *     bcm_tomahawk3_l2_addr_delete_by_vlan_gport_multi
   2793  * Purpose:
   2794  *     Purge L2 entries belong to set of (vlan,port) tuple.
   2795  * Parameters:
   2796  *     unit       -  (IN) Device unit number
   2797  *     flags      -  (IN) Only accept BCM_L2_REPLACE_DELETE, BCM_L2_REPLACE_NO_CALLBACKS.
   2798  *     num_pairs  -  (IN) Size of (vlan,port) pair array.
   2799  *     vlan       -  (IN) Reference to array of VLAN list.
   2800  *     gport      -  (IN) Reference to array of gport list.
   2801  * Returns:
   2802  *     BCM_E_XXX
   2803  * Note:
   2804  *     If one of the elements of the (vlan,gport) pair is invalid
   2805  *     (if vlan value is BCM_VLAN_INVALID or port value is BCM_GPORT_INVALID),
   2806  *     it is a wildcard.
   2807  *     Entries are removed only if BCM_L2_REPLACE_DELETE flag is used. With
   2808  *     flag BCM_L2_REPLACE_NO_CALLBACKS, l2 aging and learning are disabled 
   2809  *     during this operation.
   2810  */
   2811 
   2812 int 
   2813 bcm_tomahawk3_l2_addr_delete_by_vlan_gport_multi(int unit, uint32 flags,
   2814                                                  int num_pairs,
   2815                                                  bcm_vlan_t *vlan,
   2816                                                  bcm_gport_t *gport)
   2817 {
   2818     sal_usecs_t                   interval=0;
   2819     bcm_module_t                  mod_in, modid = 0;
   2820     bcm_port_t                    port_in, port = 0;
   2821     bcm_trunk_t                   trunk_id = 0;
   2822     int                           id = 0, ct, i;
   2823     int                           rv2 = 0, rv = BCM_E_UNAVAIL;
   2824     soc_control_t                 *soc = SOC_CONTROL(unit);
   2825     uint32                        max_modid;
   2826     _bcm_l2_vlan_port_pair_t      *mod_l2_pair_arr = NULL;
   2827     _bcm_l2_vlan_trunk_pair_t     *l2_trunk_pair_arr = NULL;
   2828     _bcm_l2_del_vlan_port_pair_t  l2_pair;
   2829     int                           alloc_size;
   2830 
   2831     /* Validate the input parameters */
   2832     if (vlan == NULL || gport == NULL || num_pairs == 0) {
   2833         return BCM_E_PARAM;
   2834     }
   2835 
   2836     /* Validate flag parameter, no action will be proceeded with extra flags */
   2837     if ((flags & ~(BCM_L2_REPLACE_DELETE | BCM_L2_REPLACE_NO_CALLBACKS | 
   2838                    BCM_L2_REPLACE_MATCH_STATIC |
   2839                    BCM_L2_REPLACE_PENDING )) != 0) {
   2840         return BCM_E_NONE;
   2841     }
   2842 
   2843     sal_memset(&l2_pair, 0x0, sizeof(l2_pair));
   2844     
   2845     /* Prepare (vlan, (mod, port)) pair */
   2846     max_modid = SOC_MODID_MAX(unit) + 1;  
   2847     alloc_size = sizeof(_bcm_l2_vlan_port_pair_t) * max_modid;
   2848     mod_l2_pair_arr = sal_alloc(alloc_size, "l2_addr_vlan_gport_multi_delete");
   2849     if (mod_l2_pair_arr == NULL) {
   2850         return BCM_E_MEMORY;
   2851     }
   2852     sal_memset(mod_l2_pair_arr, 0x0, alloc_size);
   2853 
   2854     /* Prepare (vlan, tid) pair */
   2855     l2_pair.mod_pair_arr = mod_l2_pair_arr;
   2856     alloc_size = sizeof(_bcm_l2_vlan_trunk_pair_t);
   2857     l2_trunk_pair_arr = sal_alloc(alloc_size, "l2_addr_vlan_gport_multi_delete");
   2858     if (l2_trunk_pair_arr == NULL) {
   2859         rv = BCM_E_MEMORY;
   2860         goto _free_exit;
   2861     }
   2862     sal_memset(l2_trunk_pair_arr, 0x0, alloc_size);
   2863     l2_pair.unit_pair_arr = l2_trunk_pair_arr;
   2864     
   2865     /* Assumption is that the trunk module will have the same function as below
   2866      * for getting trunk information
   2867     */
   2868     alloc_size = SHR_BITALLOCSIZE(_bcm_esw_trunk_group_num(unit));
   2869     for (i = 0; i < BCM_VLAN_MAX + 2; i++) {
   2870         l2_trunk_pair_arr->tbm[i] = sal_alloc(alloc_size, \
   2871             "l2_addr_vlan_gport_multi_delete");
   2872         if (l2_trunk_pair_arr->tbm[i] == NULL) {
   2873             rv = BCM_E_MEMORY;
   2874             goto _free_exit;
   2875         }
   2876         sal_memset(l2_trunk_pair_arr->tbm[i], 0x0, alloc_size);
   2877     }
   2878 
   2879     /* Validate vlan & gport */
   2880     for (ct = 0; ct < num_pairs; ct++) {
   2881         if (vlan[ct] == BCM_VLAN_INVALID &&
   2882             gport[ct] == BCM_GPORT_INVALID) {
   2883             rv = BCM_E_PARAM;
   2884             goto _free_exit;
   2885         }
   2886 
   2887         if (vlan[ct] != BCM_VLAN_INVALID) {
   2888             if (vlan[ct] > BCM_VLAN_MAX) {
   2889                 rv = BCM_E_PARAM;
   2890                 goto _free_exit;
   2891             }
   2892         }
   2893 
   2894         if (gport[ct] != BCM_GPORT_INVALID) {
   2895 
   2896             if (BCM_GPORT_IS_MODPORT(gport[ct])) {
   2897                 mod_in = BCM_GPORT_MODPORT_MODID_GET(gport[ct]);
   2898                 port_in = BCM_GPORT_MODPORT_PORT_GET(gport[ct]);
   2899                 modid = mod_in;
   2900                 port = port_in;
   2901             } else {
   2902                 rv = _bcm_esw_gport_resolve(unit, gport[ct],
   2903                                        &modid, &port, &trunk_id, &id);
   2904                 if (BCM_FAILURE(rv)) {
   2905                     goto _free_exit;
   2906                 }
   2907             
   2908                 if (BCM_GPORT_IS_TRUNK(gport[ct])) {
   2909                     rv = _bcm_trunk_id_validate(unit, trunk_id);
   2910                     if (BCM_FAILURE(rv)) {
   2911                         rv = BCM_E_PARAM;
   2912                         goto _free_exit;
   2913                     }
   2914                 } else {
   2915                     rv = BCM_E_PARAM;
   2916                     goto _free_exit;
   2917                 }
   2918             }
   2919         }
   2920 
   2921         if (vlan[ct] == BCM_VLAN_INVALID) {
   2922             if (BCM_GPORT_IS_TRUNK(gport[ct])) {
   2923                 SHR_BITSET(l2_pair.unit_pair_arr[0].tbm[BCM_VLAN_MAX+1], \
   2924                     trunk_id);
   2925             } else if (BCM_GPORT_IS_MODPORT(gport[ct])){
   2926                 BCM_PBMP_PORT_ADD( \
   2927                     l2_pair.mod_pair_arr[modid].pbm[BCM_VLAN_MAX+1], port);
   2928             }
   2929         } else if (gport[ct] == BCM_GPORT_INVALID) {
   2930             BCM_VLAN_VEC_SET(l2_pair.del_by_vlan_vec, vlan[ct]);
   2931         } else {
   2932             if (BCM_GPORT_IS_TRUNK(gport[ct])) {
   2933                 SHR_BITSET(l2_pair.unit_pair_arr[0].tbm[vlan[ct]], \
   2934                     trunk_id);                
   2935             } else /* if (BCM_GPORT_IS_MODPORT(gport[ct])) */{
   2936                 BCM_PBMP_PORT_ADD(l2_pair.mod_pair_arr[modid].pbm[vlan[ct]], \
   2937                     port);
   2938             }
   2939         }
   2940     }
   2941 
   2942     if (flags & BCM_L2_REPLACE_DELETE) {
   2943         _l2_dbg_matched_entries[unit] = 0;
   2944         _l2_dbg_unmatched_entries[unit] = 0;
   2945 
   2946         if (flags & BCM_L2_REPLACE_NO_CALLBACKS) {
   2947             interval = soc->l2x_interval;
   2948             rv = bcm_esw_l2_addr_freeze(unit);
   2949             if (BCM_FAILURE(rv)) {
   2950                 goto _free_exit;
   2951             }
   2952 
   2953             rv2 = soc_l2x_stop(unit);
   2954             if (rv2 < 0) {
   2955                 goto _free_exit;
   2956             }
   2957 
   2958             LOG_INFO(BSL_LS_BCM_ARL,
   2959                      (BSL_META_U(unit, "L2 Freeze and stop L2 thread\n")));
   2960         }
   2961 
   2962         l2_pair.replace_flags   = flags;
   2963 
   2964         rv = bcm_tomahawk3_l2_traverse(unit,
   2965                                        _bcm_th3_l2_vlan_gport_matched_delete,
   2966                                        &l2_pair);
   2967         if (rv == BCM_E_NONE) {
   2968             LOG_INFO(BSL_LS_BCM_ARL,
   2969                      (BSL_META_U(unit,
   2970                                  "Total number of L2 Entries: %d [Deleted:%d Left:%d]\n\r"),
   2971                       _l2_dbg_matched_entries[unit] + _l2_dbg_unmatched_entries[unit],
   2972                       _l2_dbg_matched_entries[unit], _l2_dbg_unmatched_entries[unit]));
   2973         }
   2974 
   2975         if (flags & BCM_L2_REPLACE_NO_CALLBACKS) {
   2976             LOG_INFO(BSL_LS_BCM_ARL,
   2977                      (BSL_META_U(unit, "L2 Thaw and start L2 thread\n")));
   2978 
   2979             rv2 = soc_l2x_start(unit, soc->l2x_flags, interval);
   2980             if (rv2 < 0) {
   2981                 goto _free_exit;
   2982             }
   2983 
   2984             rv2 = bcm_esw_l2_addr_thaw(unit);
   2985             if (rv2 < 0) {
   2986                 goto _free_exit;
   2987             }
   2988         }
   2989     }
   2990 
   2991 _free_exit:
   2992     _bcm_th3_l2_vlan_gport_free(unit, &l2_pair);
   2993 
   2994     if (rv < 0) {
   2995         return rv;
   2996     } else if (rv2 < 0) {
   2997         return rv2;
   2998     } else {
   2999         return rv;
   3000     }
   3001 }
   3002 
   3003 #ifdef BCM_WARM_BOOT_SUPPORT_SW_DUMP
   3004 #if 0
   3005 
   3006 /*
   3007  * Function:
   3008  *     _bcm_l2_sw_dump
   3009  * Purpose:
   3010  *     Displays L2 information maintained by software.
   3011  * Parameters:
   3012  *     unit - Device unit number
   3013  * Returns:
   3014  *     None
   3015  * Note:
   3016  *    The l2_data structure maintains registration of callbacks routines.
   3017  *    Dump of l2_data is skipped.
   3018  */
   3019 void
   3020 _bcm_l2_sw_dump(int unit)
   3021 {
   3022 
   3023     LOG_CLI((BSL_META_U(unit,
   3024                         "\nSW Information L2 - Unit %d\n"), unit));
   3025     LOG_CLI((BSL_META_U(unit,
   3026                         "  Initialized : %d\n"), _th3_l2_init[unit]));
   3027 
   3028     _bcm_th3_l2_sw_dump(unit);
   3029 
   3030     return;
   3031 }
   3032 #endif /* 0 */
   3033 #endif /* BCM_WARM_BOOT_SUPPORT_SW_DUMP */
   3034 
   3035 #ifdef BCM_WARM_BOOT_SUPPORT
   3036 /* Warmboot versions below must be as defined in src/bcm/esw/l2.c */
   3037 #define BCM_WB_VERSION_1_0                SOC_SCACHE_VERSION(1,0)
   3038 #define BCM_WB_VERSION_1_1                SOC_SCACHE_VERSION(1,1)
   3039 #define BCM_WB_DEFAULT_VERSION            BCM_WB_VERSION_1_1
   3040 
   3041 /*
   3042  * Function:
   3043  *      _bcm_th3_l2_wb_alloc
   3044  * Purpose:
   3045  *      Allocated L2 module persistent info for Level 2 Warm Boot
   3046  * Parameters:
   3047  *      unit - StrataSwitch unit number.
   3048  * Returns:
   3049  *      BCM_E_XXX
   3050  */
   3051 STATIC int
   3052 _bcm_th3_l2_wb_alloc(int unit)
   3053 {
   3054     int                         sz = 0;
   3055     soc_scache_handle_t         scache_handle;
   3056     uint8                       *scache_ptr;
   3057     int                         rv = BCM_E_NONE;
   3058     int                         stable_size = 0;
   3059     _bcm_l2_station_control_t   *station_control = NULL;
   3060     int                         sw_aging_support;
   3061     int                         underlay_max_entries = 0;
   3062 
   3063     SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size));
   3064     /* Requires extended scache support warmboot */
   3065     if (stable_size == 0) {
   3066         return BCM_E_NONE;
   3067     }
   3068 
   3069     rv = _bcm_th3_l2_station_control_get(unit, &station_control);
   3070     if (BCM_FAILURE(rv) && (rv != BCM_E_INIT)) {
   3071         return rv;
   3072     }
   3073 
   3074     /* TH3 does not support SW aging. Added only for warmboot upgrade purpose.
   3075      * See _bcm_esw_l2_wb_alloc
   3076      */
   3077     sw_aging_support = 1;
   3078 
   3079     if (sw_aging_support ||
   3080         ((!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) && station_control)) {
   3081 
   3082         SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_L2, 0);
   3083 
   3084         if (sw_aging_support) {
   3085             /* aging time */
   3086             sz += sizeof(int);
   3087         }
   3088 
   3089         if ((!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) && station_control) {
   3090             /* Underlay L2 station entry - sid/prio */
   3091             /* For TH3, l2_station_entry_max_size_get and l2_station_size_get
   3092              * would return same value, so we use l2_station_size_get
   3093              * (we have not defined bcm_th3_l2_station_max_size_get)
   3094              */
   3095             BCM_IF_ERROR_RETURN(
   3096                 bcm_th3_l2_station_size_get(unit, &underlay_max_entries));
   3097             sz += (underlay_max_entries * (sizeof(int) * 2));
   3098 
   3099         }
   3100 
   3101         rv = _bcm_esw_scache_ptr_get(unit, scache_handle, TRUE,
   3102                                      sz, &scache_ptr,
   3103                                      BCM_WB_DEFAULT_VERSION, NULL);
   3104 
   3105         if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) {
   3106             return rv;
   3107         }
   3108     }
   3109     return BCM_E_NONE;
   3110 }
   3111 
   3112 /*
   3113  * Function:
   3114  *      _bcm_th3_l2_wb_sync
   3115  * Purpose:
   3116  *      Record L2 module persistent info for Level 2 Warm Boot
   3117  * Parameters:
   3118  *      unit - StrataSwitch unit number.
   3119  * Returns:
   3120  *      BCM_E_XXX
   3121  */
   3122 int
   3123 _bcm_th3_l2_wb_sync(int unit)
   3124 {
   3125     int                         sz = 0;
   3126     soc_scache_handle_t         scache_handle;
   3127     uint8                       *scache_ptr = NULL;
   3128     int                         aging_time = 0;
   3129     _bcm_l2_station_entry_t     **entry_arr;
   3130     _bcm_l2_station_control_t   *station_control = NULL;
   3131     int                         stable_size = 0;
   3132     int                         rv = BCM_E_NONE;
   3133     int                         index = 0;
   3134     int                         init_value = 0;
   3135     int                         sw_aging_support; /* SW Learning supported */
   3136     int                         underlay_max_entries = 0;
   3137 
   3138     SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size));
   3139     /* Requires extended scache support warmboot */
   3140     if (stable_size == 0) {
   3141         return BCM_E_NONE;
   3142     }
   3143 
   3144     rv = _bcm_th3_l2_station_control_get(unit, &station_control);
   3145     if (BCM_FAILURE(rv) && (rv != BCM_E_INIT)) {
   3146         return rv;
   3147     }
   3148 
   3149     /* TH3 does not support SW aging. Added only for warmboot upgrade purpose.
   3150      * See _bcm_esw_l2_wb_sync
   3151      */
   3152     sw_aging_support = 1;
   3153 
   3154     if (sw_aging_support ||
   3155         ((!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) && station_control)) {
   3156 
   3157         SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_L2, 0);
   3158         rv = _bcm_esw_scache_ptr_get(unit, scache_handle, FALSE,
   3159                                      0, &scache_ptr,
   3160                                      BCM_WB_DEFAULT_VERSION, NULL);
   3161 
   3162         if (BCM_FAILURE(rv) && (rv != BCM_E_INTERNAL)) {
   3163             return rv;
   3164         }
   3165 
   3166         if (sw_aging_support) {
   3167             /* aging time */
   3168             BCM_IF_ERROR_RETURN(
   3169                 _bcm_tomahawk3_l2_age_timer_get(unit, &aging_time));
   3170             sz = sizeof(int);
   3171             sal_memcpy(scache_ptr, &aging_time, sz);
   3172             scache_ptr += sz;
   3173         }
   3174 
   3175         if ((!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) && station_control) {
   3176             BCM_IF_ERROR_RETURN(
   3177                 bcm_th3_l2_station_size_get(unit, &underlay_max_entries));
   3178             /* Underlay L2 station entry - sid/prio */
   3179             entry_arr = (station_control->entry_arr);
   3180 
   3181             for (index = 0; index < underlay_max_entries; index++) {
   3182                 if (entry_arr[index]) {
   3183                     sal_memcpy(scache_ptr,
   3184                                &(entry_arr[index]->sid), sizeof(int));
   3185                     scache_ptr += sizeof(int);
   3186 
   3187                     sal_memcpy(scache_ptr,
   3188                                &(entry_arr[index]->prio), sizeof(int));
   3189                     scache_ptr += sizeof(int);
   3190                 } else {
   3191                     sal_memcpy(scache_ptr, &init_value, sizeof(int));
   3192                     scache_ptr += sizeof(int);
   3193 
   3194                     sal_memcpy(scache_ptr, &init_value, sizeof(int));
   3195                     scache_ptr += sizeof(int);
   3196                 }
   3197             }
   3198         }
   3199     }
   3200 
   3201     return BCM_E_NONE;
   3202 }
   3203 
   3204 /*
   3205  * Function:
   3206  *      _bcm_th3_l2_wb_recover
   3207  * Purpose:
   3208  *      Recover L2 module persistent info for Level 2 Warm Boot
   3209  * Parameters:
   3210  *      unit - StrataSwitch unit number.
   3211  * Returns:
   3212  *      BCM_E_XXX
   3213  */
   3214 STATIC int
   3215 _bcm_th3_l2_wb_recover(int unit)
   3216 {
   3217     soc_scache_handle_t         scache_handle;
   3218     uint8                       *scache_ptr = NULL;
   3219     uint16                      recovered_ver = 0;
   3220     int                         aging_time = 0;
   3221     int                         rv = BCM_E_NONE;
   3222     int                         additional_scache_size = 0;
   3223     int                         sw_aging_support;
   3224     int                         underlay_max_entries = 0;
   3225     _bcm_l2_station_entry_t     **entry_arr;
   3226     _bcm_l2_station_control_t   *station_control = NULL;
   3227     int                         index = 0;
   3228     int                         sid = 0;
   3229     int                         pri = 0;
   3230     int                         cur_last_sid = 0;
   3231     int                         stable_size = 0;
   3232 
   3233     SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size));
   3234     /* Requires extended scache support warmboot */
   3235     if (stable_size == 0) {
   3236         return BCM_E_NONE;
   3237     }
   3238 
   3239     rv = _bcm_th3_l2_station_control_get(unit, &station_control);
   3240     if (BCM_FAILURE(rv) && (rv != BCM_E_INIT)) {
   3241         return rv;
   3242     }
   3243 
   3244     /* TH3 does not support SW aging. Added only for warmboot upgrade purpose.
   3245      * See _bcm_esw_l2_wb_recover
   3246      */
   3247     sw_aging_support = 1;
   3248 
   3249     if (sw_aging_support ||
   3250         ((!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) && station_control)) {
   3251 
   3252         SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_L2, 0);
   3253         rv = _bcm_esw_scache_ptr_get(unit, scache_handle, FALSE,
   3254                                      0, &scache_ptr,
   3255                                      BCM_WB_DEFAULT_VERSION, &recovered_ver);
   3256         if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) {
   3257             return rv;
   3258         } else if (BCM_E_NOT_FOUND == rv) {
   3259             return _bcm_th3_l2_wb_alloc(unit);
   3260         }
   3261 
   3262         if (scache_ptr != NULL) {
   3263             if (sw_aging_support) {
   3264                 if (recovered_ver >= BCM_WB_VERSION_1_0) {
   3265                     /* aging time */
   3266                     sal_memcpy(&aging_time, scache_ptr, sizeof(int));
   3267                     BCM_IF_ERROR_RETURN(
   3268                         _bcm_tomahawk3_l2_age_timer_set(unit, aging_time,
   3269                                                         aging_time > 0));
   3270                     scache_ptr += sizeof(int);
   3271                 } else {
   3272                     additional_scache_size += sizeof(int);
   3273                 }
   3274             }
   3275 
   3276             if ((!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) && station_control) {
   3277                 /* We use bcm_th3_l2_station_size_get since the max_size_get
   3278                  * version will be the same as size_get
   3279                  */
   3280                 BCM_IF_ERROR_RETURN(
   3281                     bcm_th3_l2_station_size_get(unit, &underlay_max_entries));
   3282 
   3283                 /* Recover overlay/underlay L2 station entry */
   3284                 if (recovered_ver >= BCM_WB_VERSION_1_1) {
   3285                     entry_arr = (station_control->entry_arr);
   3286 
   3287                     for (index = 0; index < underlay_max_entries; index++) {
   3288                         sal_memcpy(&sid, scache_ptr, sizeof(int));
   3289                         scache_ptr += sizeof(int);
   3290 
   3291                         sal_memcpy(&pri, scache_ptr, sizeof(int));
   3292                         scache_ptr += sizeof(int);
   3293 
   3294                         if (sid > cur_last_sid) {
   3295                             cur_last_sid = sid;
   3296                         }
   3297 
   3298                         if (entry_arr[index]) {
   3299                             if (0 == sid) {
   3300                                 /*
   3301                                  * Only recover the L2 station entries created
   3302                                  * by bcm_l2_station APIs
   3303                                  */
   3304                                 if (index < station_control->entries_total) {
   3305                                     if (NULL != entry_arr[index]->tcam_ent) {
   3306                                         sal_free(entry_arr[index]->tcam_ent);
   3307                                     }
   3308 
   3309                                     sal_free(entry_arr[index]);
   3310 
   3311                                     entry_arr[index] = NULL;
   3312                                     station_control->entry_count--;
   3313                                     station_control->entries_free++;
   3314                                 }
   3315                             } else {
   3316                                 entry_arr[index]->sid = sid;
   3317                                 entry_arr[index]->prio = pri;
   3318                             }
   3319                         }
   3320                     }
   3321 
   3322                     rv = _bcm_th3_l2_station_entry_last_sid_set(unit, FALSE,
   3323                                                           cur_last_sid);
   3324                     if (BCM_FAILURE(rv)) {
   3325                        return rv;
   3326                     }
   3327                 } else {
   3328                     /* Underlay L2 station entry - sid/prio */
   3329                     additional_scache_size +=
   3330                         (underlay_max_entries *(sizeof(int) * 2));
   3331                 }
   3332             }
   3333 
   3334             if (additional_scache_size > 0) {
   3335                 rv = soc_scache_realloc(unit, scache_handle,
   3336                                         additional_scache_size);
   3337                 if(BCM_FAILURE(rv)) {
   3338                    return rv;
   3339                 }
   3340             }
   3341         }
   3342     }
   3343 
   3344     return BCM_E_NONE;
   3345 }
   3346 #endif /* BCM_WARM_BOOT_SUPPORT */
   3347 
   3348 /*
   3349  * Function:
   3350  *	bcm_tomahawk3_l2_addr_add
   3351  * Description:
   3352  *	Add a MAC address to the Switch Address Resolution Logic (ARL)
   3353  *	port with the given VLAN ID and parameters.
   3354  * Parameters:
   3355  *	unit - StrataSwitch PCI device unit number (driver internal).
   3356  *	l2addr - Pointer to bcm_l2_addr_t containing all valid fields
   3357  * Returns:
   3358  *	BCM_E_NONE		Success
   3359  *	BCM_E_INTERNAL		Chip access failure
   3360  * Notes:
   3361  *	Use CMIC_PORT(unit) to associate the entry with the CPU.
   3362  *	Use flag of BCM_L2_COPY_TO_CPU to send a copy to the CPU.
   3363  *      Use flag of BCM_L2_TRUNK_MEMBER to set trunking (TGID must be
   3364  *      passed as well with non-zero trunk group ID)
   3365  */
   3366 int
   3367 bcm_tomahawk3_l2_addr_add(int unit, bcm_l2_addr_t *l2addr)
   3368 {
   3369     TH3_L2_INIT(unit);
   3370 
   3371 
   3372     /* Input parameters check. */
   3373     if (NULL == l2addr) {
   3374         return (BCM_E_PARAM);
   3375     }
   3376 
   3377     if (l2addr->flags & BCM_L2_DISCARD_DST) {
   3378         if (MAC_IS_MCAST(l2addr->mac)) {
   3379             return (BCM_E_UNAVAIL);
   3380         }
   3381     }
   3382 
   3383     if (l2addr->flags & BCM_L2_LOCAL_CPU) {
   3384         l2addr->port = CMIC_PORT(unit);
   3385         l2addr->modid = 0;
   3386     }
   3387 
   3388     if (l2addr->flags & BCM_L2_TRUNK_MEMBER) {
   3389         BCM_IF_ERROR_RETURN(_bcm_trunk_id_validate(unit, l2addr->tgid));
   3390     }
   3391 
   3392     if (SOC_L2X_GROUP_ENABLE_GET(unit)) {
   3393         /* soc_feature_overlaid_address_class should be enabled */
   3394         if (soc_feature(unit, soc_feature_overlaid_address_class) &&
   3395             !BCM_L2_PRE_SET(l2addr->flags)) {
   3396             if ((l2addr->group > SOC_OVERLAID_ADDR_CLASS_MAX(unit)) ||
   3397                 (l2addr->group < 0)) {
   3398                 return (BCM_E_PARAM);
   3399             }
   3400         } else if ((l2addr->group > SOC_ADDR_CLASS_MAX(unit)) ||
   3401                    (l2addr->group < 0)) {
   3402             return (BCM_E_PARAM);
   3403         }
   3404         if (!BCM_PBMP_IS_NULL(l2addr->block_bitmap)) {
   3405             return (BCM_E_PARAM);
   3406         }
   3407     } else {
   3408         if (l2addr->group)  {
   3409             return (BCM_E_PARAM);
   3410         }
   3411     }
   3412 
   3413     SOC_IF_ERROR_RETURN
   3414 	(mbcm_driver[unit]->mbcm_l2_addr_add(unit, l2addr));
   3415 
   3416     return BCM_E_NONE;
   3417 }
   3418 
   3419 /*
   3420  * Function:
   3421  *	bcm_tomahawk3_l2_addr_delete
   3422  * Description:
   3423  *	Delete an L2 address (MAC+VLAN) from the device
   3424  * Parameters:
   3425  *	unit - device unit
   3426  *	mac  - MAC address to delete
   3427  *	vid  - VLAN id
   3428  * Returns:
   3429  *	BCM_E_XXX
   3430  */
   3431 
   3432 int
   3433 bcm_tomahawk3_l2_addr_delete(int unit, bcm_mac_t mac, bcm_vlan_t vid)
   3434 {
   3435     TH3_L2_INIT(unit);
   3436 
   3437     /* Calls bcm_th3_l2_addr_delete defined above */
   3438     return mbcm_driver[unit]->mbcm_l2_addr_delete(unit, mac, vid);
   3439 }
   3440 
   3441 /*
   3442  * Function:
   3443  *	bcm_tomahawk3_l2_addr_get
   3444  * Description:
   3445  *	Given a MAC address and VLAN ID, check if the entry is present
   3446  *	in the L2 table, and if so, return all associated information.
   3447  * Parameters:
   3448  *	unit - StrataSwitch PCI device unit number (driver internal).
   3449  *	mac - input MAC address to search
   3450  *	vid - input VLAN ID to search
   3451  *	l2addr - Pointer to bcm_l2_addr_t structure to receive results
   3452  * Returns:
   3453  *	BCM_E_NONE		Success (l2addr filled in)
   3454  *	BCM_E_PARAM		Illegal parameter (NULL pointer)
   3455  *	BCM_E_INTERNAL		Chip access failure
   3456  *	BCM_E_NOT_FOUND	        Address not found (l2addr not filled in)
   3457  */
   3458 
   3459 int
   3460 bcm_tomahawk3_l2_addr_get(int unit, sal_mac_addr_t mac,
   3461 		                  bcm_vlan_t vid, bcm_l2_addr_t *l2addr)
   3462 {
   3463     TH3_L2_INIT(unit);
   3464 
   3465     /* Calls bcm_th3_l2_addr_get defined above */
   3466     SOC_IF_ERROR_RETURN(
   3467         mbcm_driver[unit]->mbcm_l2_addr_get(unit, mac, vid, l2addr));
   3468 
   3469     return BCM_E_NONE;
   3470 }
   3471 
   3472 /*
   3473  * Function:
   3474  * 	_bcm_th3_l2_addr_callback
   3475  * Description:
   3476  *	Callback used with chip addr registration functions.
   3477  *	This callback calls all the top level client callbacks.
   3478  * Parameters:
   3479  *	unit - StrataSwitch PCI device unit number (driver internal).
   3480  *	l2addr
   3481  *	insert
   3482  *	userdata
   3483  * Returns:
   3484  */
   3485 STATIC void
   3486 _bcm_th3_l2_addr_callback(int unit,
   3487 		                  bcm_l2_addr_t *l2addr,
   3488 		                  int insert,
   3489 		                  void *userdata)
   3490 {
   3491     th3_l2_data_t *ad = &th3_l2_data[unit];
   3492     int i;
   3493 
   3494     if (ad->l2_mutex == NULL) {
   3495         return;
   3496     }
   3497 
   3498     L2_LOCK(unit);
   3499     for(i = 0; i < L2_CB_MAX; i++) {
   3500         if(ad->cb[i].fn) {
   3501             ad->cb[i].fn(unit, l2addr, insert, ad->cb[i].fn_data);
   3502         }
   3503     }
   3504     L2_UNLOCK(unit);
   3505 }
   3506 
   3507 /*
   3508  * Function:
   3509  *	bcm_tomahawk3_l2_addr_register
   3510  * Description:
   3511  *	Register a callback routine that will be called whenever
   3512  *	an entry is inserted into or deleted from the L2 address table
   3513  * Parameters:
   3514  *	unit - StrataSwitch PCI device unit number (driver internal)
   3515  *	fn - Callback function of type bcm_l2_addr_callback_t
   3516  *	fn_data - Arbitrary value passed to callback along with messages
   3517  * Returns:
   3518  *	BCM_E_NONE		Success, handle valid
   3519  *	BCM_E_MEMORY		Out of memory
   3520  *	BCM_E_INTERNAL		Chip access failure
   3521  */
   3522 
   3523 int
   3524 bcm_tomahawk3_l2_addr_register(int unit,
   3525                                bcm_l2_addr_callback_t fn,
   3526                                void *fn_data)
   3527 {
   3528     th3_l2_data_t *ad = &th3_l2_data[unit];
   3529     int i;
   3530     int rv = BCM_E_NONE;
   3531     int usec;
   3532 
   3533     TH3_L2_INIT(unit);
   3534 
   3535     _bcm_th3_l2_cbs[unit] = _bcm_th3_l2_addr_callback;
   3536     _bcm_th3_l2_cb_data[unit] = NULL;
   3537 
   3538     L2_MUTEX(unit);
   3539     L2_LOCK(unit);
   3540 
   3541     /* Start L2x thread if it isn't running already. */
   3542     if (!soc_l2x_running(unit, NULL, NULL)) {
   3543         /* Use default value. Even for bcmsim we need interval to be
   3544          * sufficiently small to track L2X table updates
   3545          */
   3546         usec = SOC_L2X_INTERVAL_DEFAULT;
   3547         usec = soc_property_get(unit, spn_L2XMSG_THREAD_USEC, usec);
   3548         rv = soc_l2x_start(unit, 0, usec);
   3549         if ((BCM_FAILURE(rv)) && (rv != BCM_E_UNAVAIL)) {
   3550             _bcm_th3_l2_cbs[unit] = NULL;
   3551             _bcm_th3_l2_cb_data[unit] = NULL;
   3552             L2_UNLOCK(unit);
   3553             return(rv);
   3554         }
   3555         ad->flags |= _BCM_TH3_L2X_THREAD_STOP;
   3556     }
   3557 
   3558     /* See if the function is already registered (with same data) */
   3559     for (i = 0; i < L2_CB_MAX; i++) {
   3560         if (ad->cb[i].fn == fn && ad->cb[i].fn_data == fn_data) {
   3561             L2_UNLOCK(unit);
   3562             return BCM_E_NONE;
   3563         }
   3564     }
   3565 
   3566     /* Not found; add to list. */
   3567     for (i = 0; i < L2_CB_MAX; i++) {
   3568         if (ad->cb[i].fn == NULL) {
   3569             ad->cb[i].fn = fn;
   3570             ad->cb[i].fn_data = fn_data;
   3571             ad->cb_count++;
   3572             break;
   3573 	    }
   3574     }
   3575 
   3576     L2_UNLOCK(unit);
   3577     return i >= L2_CB_MAX ? BCM_E_RESOURCE : BCM_E_NONE;
   3578 }
   3579 
   3580 /*
   3581  * Function:
   3582  *	bcm_tomahawk3_l2_addr_unregister
   3583  * Description:
   3584  *	Unregister a previously registered callback routine.
   3585  * Parameters:
   3586  *	unit - StrataSwitch PCI device unit number (driver internal).
   3587  *	fn - Same callback function used to register callback
   3588  *	fn_data - Same arbitrary value used to register callback
   3589  * Returns:
   3590  *	BCM_E_NONE		Success, handle valid
   3591  *	BCM_E_MEMORY		Out of memory
   3592  *	BCM_E_INTERNAL		Chip access failure
   3593  * Notes:
   3594  *	Both callback and userdata must match from original register call.
   3595  */
   3596 int
   3597 bcm_tomahawk3_l2_addr_unregister(int unit,
   3598                                  bcm_l2_addr_callback_t fn,
   3599                                  void *fn_data)
   3600 {
   3601     th3_l2_data_t *ad = &th3_l2_data[unit];
   3602     int rv = BCM_E_NOT_FOUND;
   3603     int	i;
   3604 
   3605     TH3_L2_INIT(unit);
   3606     L2_MUTEX(unit);
   3607     if (_bcm_th3_l2_cb_check[unit] != NULL) {
   3608         sal_sem_take(_bcm_th3_l2_cb_check[unit], sal_sem_FOREVER);
   3609     }
   3610     L2_LOCK(unit);
   3611 
   3612     for (i = 0; i < L2_CB_MAX; i++) {
   3613         if((ad->cb[i].fn == fn) && (ad->cb[i].fn_data == fn_data)) {
   3614             rv = BCM_E_NONE;
   3615             ad->cb[i].fn = NULL;
   3616             ad->cb[i].fn_data = NULL;
   3617             ad->cb_count--;
   3618             if (ad->cb_count == 0) {
   3619                 _bcm_th3_l2_cbs[unit] = NULL;
   3620                 _bcm_th3_l2_cb_data[unit] = NULL;
   3621 
   3622                 /* Stop l2x thread if callback registration started it. */
   3623                 if (ad->flags & _BCM_TH3_L2X_THREAD_STOP) {
   3624                     rv = soc_l2x_stop(unit);
   3625                     ad->flags &= ~_BCM_TH3_L2X_THREAD_STOP;
   3626                 }
   3627             }
   3628         }
   3629     }
   3630 
   3631     L2_UNLOCK(unit);
   3632     if (_bcm_th3_l2_cb_check[unit] != NULL) {
   3633         sal_sem_give(_bcm_th3_l2_cb_check[unit]);
   3634     }
   3635     return (rv);
   3636 }
   3637 
   3638 /*
   3639  * Function:
   3640  *     bcm_tomahawk3_l2_station_add
   3641  * Description:
   3642  *     Add an entry to L2 Station Table      
   3643  * Parameters:
   3644  *     unit         - (IN) BCM device number
   3645  *     station_id   - (IN/OUT) Station ID
   3646  *     station      - (IN) Pointer to station address information
   3647  * Return:
   3648  *     BCM_E_XXX
   3649  */
   3650 int
   3651 bcm_tomahawk3_l2_station_add(int unit, int *station_id,
   3652                              bcm_l2_station_t *station)
   3653 {
   3654     int rv = BCM_E_UNAVAIL;
   3655 
   3656     rv = bcm_th3_l2_station_add(unit, station_id, station);
   3657 
   3658     return rv;
   3659 }
   3660 
   3661 /*
   3662  * Function:
   3663  *     bcm_tomahawk3_l2_station_delete
   3664  * Description:
   3665  *     Delete an entry from L2 Station Table
   3666  * Parameters:
   3667  *     unit         - (IN) BCM device number
   3668  *     station_id   - (IN) Station ID
   3669  * Return:
   3670  *     BCM_E_XXX
   3671  */
   3672 int
   3673 bcm_tomahawk3_l2_station_delete(int unit, int station_id)
   3674 {
   3675 
   3676     int rv = BCM_E_UNAVAIL;
   3677 
   3678     rv = bcm_th3_l2_station_delete(unit, station_id);
   3679 
   3680     return (rv);
   3681 }
   3682 
   3683 /*
   3684  * Function:
   3685  *     bcm_tomahawk3_l2_station_delete_all
   3686  * Description:
   3687  *     Clear all L2 Station Table entries
   3688  * Parameters:
   3689  *     unit - (IN) BCM device number
   3690  * Return:
   3691  *     BCM_E_XXX
   3692  */
   3693 int
   3694 bcm_tomahawk3_l2_station_delete_all(int unit)
   3695 {
   3696     int rv = BCM_E_UNAVAIL;
   3697 
   3698     rv = bcm_th3_l2_station_delete_all(unit);
   3699 
   3700     return (rv);
   3701 }
   3702 
   3703 /*
   3704  * Function:
   3705  *     bcm_tomahawk3_l2_station_get
   3706  * Description:
   3707  *     Get L2 station entry detail from Station Table
   3708  * Parameters:
   3709  *     unit         - (IN) BCM device number
   3710  *     station_id   - (IN) Station ID
   3711  *     station      - (OUT) Pointer to station address information
   3712  * Return:
   3713  *     BCM_E_XXX
   3714  */
   3715 int
   3716 bcm_tomahawk3_l2_station_get(int unit, int station_id,
   3717                              bcm_l2_station_t *station)
   3718 {
   3719     int rv = BCM_E_UNAVAIL;
   3720 
   3721     rv = bcm_th3_l2_station_get(unit, station_id, station);
   3722 
   3723     return (rv);
   3724 }
   3725 
   3726 /*
   3727  * Function:
   3728  *     bcm_tomahawk3_l2_station_size_get
   3729  * Description:
   3730  *     Get size of L2 Station Table
   3731  * Parameters:
   3732  *     unit - (IN) BCM device number
   3733  *     size - (OUT) L2 Station table size
   3734  * Return:
   3735  *     BCM_E_XXX
   3736  */
   3737 int
   3738 bcm_tomahawk3_l2_station_size_get(int unit, int *size)
   3739 {
   3740     int rv = BCM_E_UNAVAIL;
   3741 
   3742     rv = bcm_th3_l2_station_size_get(unit, size);
   3743 
   3744     return (rv);
   3745 }
   3746 
   3747 /*
   3748  * Function:
   3749  *     bcm_tomahawk3_l2_station_traverse
   3750  * Description:
   3751  *     Traverse L2 station entry from Station Table
   3752  * Parameters:
   3753  *     unit         - (IN) BCM device number
   3754  *     trav_fn   -  (IN) Customer defines function is used to traverse
   3755  *     user_data - (IN) Pointer to information of customer.
   3756  * Return:
   3757  *     BCM_E_XXX
   3758  */
   3759 int 
   3760 bcm_tomahawk3_l2_station_traverse(int unit, bcm_l2_station_traverse_cb trav_fn,
   3761                                   void *user_data)
   3762 {
   3763     int rv = BCM_E_UNAVAIL;
   3764 
   3765     rv = bcm_th3_l2_station_traverse(unit, trav_fn, user_data);
   3766 
   3767     return (rv);
   3768 }
   3769 
   3770 /*
   3771  * Function:
   3772  *      bcm_tomahawk3_l2_tunnel_add
   3773  * Purpose:
   3774  *    Add a (MAC, VLAN) for tunnel/MPLS processing, frames
   3775  *    destined to (MAC, VLAN) is subjected to TUNNEL/MPLS processing.
   3776  * Parameters:
   3777  *      unit - StrataXGS unit number
   3778  *      mac  - MAC address
   3779  *      vlan - VLAN ID
   3780  */
   3781 int
   3782 bcm_tomahawk3_l2_tunnel_add(int unit, bcm_mac_t mac, bcm_vlan_t vlan)
   3783 {
   3784     TH3_L2_INIT(unit);
   3785 
   3786 #if defined(BCM_MPLS_SUPPORT) && defined(INCLUDE_L3)
   3787     VLAN_CHK_ID(unit, vlan);
   3788 
   3789     return bcm_td_metro_myStation_add(unit, mac, vlan, -1, 1);
   3790 #else
   3791     return BCM_E_UNAVAIL;
   3792 #endif
   3793 }
   3794 
   3795 /*
   3796  * Function:
   3797  *      bcm_tomahawk3_l2_tunnel_delete
   3798  * Purpose:
   3799  *      Remove a tunnel processing indicator for an L2 address
   3800  * Parameters:
   3801  *      unit - StrataXGS unit number
   3802  *      mac  - MAC address
   3803       vlan - VLAN ID
   3804  */
   3805 
   3806 int
   3807 bcm_tomahawk3_l2_tunnel_delete(int unit, bcm_mac_t mac, bcm_vlan_t vlan)
   3808 {
   3809     TH3_L2_INIT(unit);
   3810 
   3811 #if defined(BCM_MPLS_SUPPORT) && defined(INCLUDE_L3)
   3812     VLAN_CHK_ID(unit, vlan);
   3813     return bcm_td_metro_myStation_delete(unit, mac, vlan, -1, 1);
   3814 #else
   3815     return BCM_E_UNAVAIL;
   3816 #endif
   3817 }
   3818 
   3819 /*
   3820  * Function:
   3821  *      bcm_tomahawk3_l2_tunnel_delete_all
   3822  * Purpose:
   3823  *      Remove all tunnel processing indicating L2 addresses
   3824  * Parameters:
   3825  *      unit - StrataXGS unit number
   3826  */
   3827 
   3828 int
   3829 bcm_tomahawk3_l2_tunnel_delete_all(int unit)
   3830 {
   3831     TH3_L2_INIT(unit);
   3832 
   3833 #if defined(BCM_MPLS_SUPPORT) && defined(INCLUDE_L3)
   3834     return bcm_td_metro_myStation_delete_all(unit);
   3835 #else
   3836     return BCM_E_UNAVAIL;
   3837 #endif
   3838 }
   3839 #endif /* BCM_TOMAHAWK3_SUPPORT */