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

l2xmsg.c (113584B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * File:	l2xmsg.c
      8  * Purpose:	Provide a reliable stream of L2 insert/delete messages.
      9  *
     10  * This module monitors the L2X table for changes and performs callbacks
     11  * for each insert, delete, or port movement that is detected.
     12  *
     13  * There is a time lag from the actual table change to the callback
     14  * because the l2xmsg task scans the L2X table only periodically.
     15  */
     16 
     17 #include <sal/core/libc.h>
     18 #include <shared/alloc.h>
     19 #include <sal/core/spl.h>
     20 #include <sal/core/time.h>
     21 #include <shared/bsl.h>
     22 #include <soc/mem.h>
     23 #include <soc/debug.h>
     24 #include <soc/cm.h>
     25 #include <soc/drv.h>
     26 #include <soc/l2x.h>
     27 #include <soc/ism_hash.h>
     28 #include <soc/triumph3.h>
     29 
     30 #ifdef BCM_TRIUMPH3_SUPPORT
     31 
     32 #define L2X_ENTRY_EQL(unit, e1, e2, hit) \
     33     (!_soc_mem_cmp_tr3_l2x_sync(unit, (void *) e1, (void *) e2, hit))
     34 #define EXT_L2X_1_ENTRY_EQL(unit, e1, e2, hit) \
     35     (!_soc_mem_cmp_tr3_ext_l2x_1_sync(unit, (void *) e1, (void *) e2, hit))
     36 #define EXT_L2X_2_ENTRY_EQL(unit, e1, e2, hit) \
     37     (!_soc_mem_cmp_tr3_ext_l2x_2_sync(unit, (void *) e1, (void *) e2, hit))
     38 
     39 #define L2X_IS_VALID_ENTRY(_u, _mem, _e, bitf)  \
     40            soc_mem_field32_get((_u), (_mem), (_e), bitf)
     41 
     42 
     43 STATIC void _soc_tr3_l2x_thread(void *unit_vp);
     44 
     45 #define SOC_MEM_L2_INT_LOCK(unit) \
     46     soc_mem_lock(unit, L2_ENTRY_1m); \
     47     soc_mem_lock(unit, L2_ENTRY_2m);
     48 
     49 #define SOC_MEM_L2_INT_UNLOCK(unit) \
     50     soc_mem_unlock(unit, L2_ENTRY_2m); \
     51     soc_mem_unlock(unit, L2_ENTRY_1m);
     52 
     53 #define SOC_MEM_L2_EXT_1_LOCK(unit) \
     54     soc_mem_lock(unit, EXT_L2_ENTRY_1m);
     55 
     56 #define SOC_MEM_L2_EXT_1_UNLOCK(unit) \
     57     soc_mem_unlock(unit, EXT_L2_ENTRY_1m);
     58 
     59 #define SOC_MEM_L2_EXT_2_LOCK(unit) \
     60     soc_mem_lock(unit, EXT_L2_ENTRY_2m);
     61 
     62 #define SOC_MEM_L2_EXT_2_UNLOCK(unit) \
     63     soc_mem_unlock(unit, EXT_L2_ENTRY_2m);
     64 
     65 #define SOC_TR3_L2X_BUCKET_SIZE 4
     66 
     67 /****************************************************************************
     68  *
     69  * L2X Message Registration
     70  */
     71 
     72 #define L2X_CB_MAX 3
     73 
     74 typedef struct l2x_cb_entry_s {
     75     soc_l2_entry_cb_fn fn;
     76     void               *fn_data;
     77 } l2_entry_cb_entry_t;
     78 
     79 typedef struct l2x_data_s {
     80     uint8          enabled; /* Set to true if a L2 data store is being used, 
     81                                applicable for POLL mode */
     82     uint8          int_avail;
     83     uint8          ext1_avail;
     84     uint8          ext2_avail;
     85     l2_entry_cb_entry_t cb[L2X_CB_MAX];
     86     int            cb_count;
     87     /* Internal ISM based memory: We manage type 1 and 2 using a single set */
     88     int            entry_bytes_int;
     89     int            entry_words_int;
     90     uint32         *shadow_tab_int;
     91     SHR_BITDCL     *del_map_int;
     92     SHR_BITDCL     *cb_map_int;
     93     /* External ESM based memories: Two sets for type 1 and type 2 respectively */
     94     int            entry_bytes_ext1;
     95     int            entry_words_ext1;
     96     uint32         *shadow_tab_ext1;
     97     SHR_BITDCL     *del_map_ext1;
     98     SHR_BITDCL     *cb_map_ext1;
     99     int            entry_bytes_ext2;
    100     int            entry_words_ext2;
    101     uint32         *shadow_tab_ext2;
    102     SHR_BITDCL     *del_map_ext2;
    103     SHR_BITDCL     *cb_map_ext2;
    104 } l2_entry_data_t;
    105 
    106 static l2_entry_data_t tr3_l2x_data[SOC_MAX_NUM_DEVICES];
    107 
    108 #define L2X_ENTRY_CALLBACK_SET(_u_, _index_)                     \
    109 {                                                                \
    110     SHR_BITSET(tr3_l2x_data[(_u_)].cb_map_int, (_index_));       \
    111     LOG_INFO(BSL_LS_SOC_ARL, \
    112              (BSL_META_U(unit, \
    113                          "set_entry_callback: u:%d i=%d\n"),      \
    114                          _u_, _index_));                                   \
    115 }                                                                
    116                                                                  
    117 #define L2X_ENTRY_DELETED_SET(_u_, _index_)                      \
    118 {                                                                \
    119     SHR_BITSET(tr3_l2x_data[(_u_)].del_map_int, (_index_));      \
    120     LOG_VERBOSE(BSL_LS_SOC_ARL, \
    121                 (BSL_META_U(unit, \
    122                             "set_entry_deleted: u:%d i=%d\n"),       \
    123                             _u_, _index_));                                   \
    124 }                                                                
    125 
    126 #define EXT_L2X_1_ENTRY_CALLBACK_SET(_u_, _index_)               \
    127 {                                                                \
    128     SHR_BITSET(tr3_l2x_data[(_u_)].cb_map_ext1, (_index_));      \
    129     LOG_INFO(BSL_LS_SOC_ARL, \
    130              (BSL_META_U(unit, \
    131                          "set_entry_callback: u:%d i=%d\n"),      \
    132                          _u_, _index_));                                   \
    133 }                                                                
    134                                                                  
    135 #define EXT_L2X_1_ENTRY_DELETED_SET(_u_, _index_)                \
    136 {                                                                \
    137     SHR_BITSET(tr3_l2x_data[(_u_)].del_map_ext1, (_index_));     \
    138     LOG_VERBOSE(BSL_LS_SOC_ARL, \
    139                 (BSL_META_U(unit, \
    140                             "set_entry_deleted: u:%d i=%d\n"),       \
    141                             _u_, _index_));                                   \
    142 }                                                                
    143 
    144 #define EXT_L2X_2_ENTRY_CALLBACK_SET(_u_, _index_)               \
    145 {                                                                \
    146     SHR_BITSET(tr3_l2x_data[(_u_)].cb_map_ext2, (_index_));      \
    147     LOG_INFO(BSL_LS_SOC_ARL, \
    148              (BSL_META_U(unit, \
    149                          "set_entry_callback: u:%d i=%d\n"),      \
    150                          _u_, _index_));                                   \
    151 }                                                                
    152                                                                  
    153 #define EXT_L2X_2_ENTRY_DELETED_SET(_u_, _index_)                \
    154 {                                                                \
    155     SHR_BITSET(tr3_l2x_data[(_u_)].del_map_ext2, (_index_));     \
    156     LOG_VERBOSE(BSL_LS_SOC_ARL, \
    157                 (BSL_META_U(unit, \
    158                             "set_entry_deleted: u:%d i=%d\n"),       \
    159                             _u_, _index_));                                   \
    160 }                                                                
    161                                                                  
    162 #define L2X_IS_CPU_DELETED(_u_, _index_)                         \
    163             SHR_BITGET(tr3_l2x_data[(_u_)].del_map_int, (_index_))
    164 
    165 #define SOC_L2X_TGID_TRUNK_INDICATOR(unit) \
    166         SOC_IS_RAVEN(unit) ? 0x40 : 0x20
    167 #define SOC_L2X_TGID_PORT_TRUNK_MASK           0x1f
    168 #define SOC_L2X_TGID_PORT_TRUNK_MASK_HI        0x60
    169 
    170 /*
    171  * Function:
    172  *	soc_l2_entry_register
    173  * Purpose:
    174  *	Register a callback routine to be notified of all inserts,
    175  *	deletes, and updates to the L2X table.
    176  * Parameters:
    177  *	unit - StrataSwitch unit number
    178  *	fn - Callback function to register
    179  *	fn_data - Extra data passed to callback function
    180  * Returns:
    181  *	SOC_E_NONE - Success
    182  *	SOC_E_MEMORY - Too many callbacks registered
    183  */
    184 
    185 int
    186 soc_l2_entry_register(int unit, soc_l2_entry_cb_fn fn, void *fn_data)
    187 {
    188     l2_entry_data_t *ad = &tr3_l2x_data[unit];
    189     int             i;
    190 #ifdef BCM_XGS3_SWITCH_SUPPORT
    191     soc_control_t *soc = SOC_CONTROL(unit);
    192     int           mode;
    193 
    194     mode = soc_property_get(unit, spn_L2XMSG_MODE, L2MODE_POLL);
    195 
    196     if ((mode == L2MODE_FIFO) && !soc_feature(unit, soc_feature_l2_modfifo)) {
    197         mode = L2MODE_POLL;
    198     }
    199 
    200     if ((mode == L2MODE_POLL) && soc->l2x_external) {
    201         /* Not supported for external L2 memory configuration. */
    202         return SOC_E_UNAVAIL;
    203     }
    204 #endif
    205 
    206     if (!soc_feature(unit, soc_feature_arl_hashed)) {
    207         return SOC_E_UNAVAIL;
    208     }
    209 
    210     if (ad->cb_count >= L2X_CB_MAX) {
    211         return SOC_E_MEMORY;
    212     }
    213 
    214     for (i = 0; i < ad->cb_count; i++) {
    215         if ((ad->cb[i].fn == fn &&
    216              ad->cb[i].fn_data == fn_data)) {
    217             return SOC_E_NONE; /* Already registered */
    218         }
    219     }
    220 
    221     ad->cb[ad->cb_count].fn = fn;
    222     ad->cb[ad->cb_count].fn_data = fn_data;
    223 
    224     ad->cb_count++;
    225 
    226     return SOC_E_NONE;
    227 }
    228 
    229 /*
    230  * Function:
    231  *	soc_l2_entry_unregister
    232  * Purpose:
    233  *  Unregister a callback routine; requires same args as when registered
    234  * Parameters:
    235  *  unit - StrataSwitch unit number
    236  *  fn - Callback function to unregister; NULL to unregister all
    237  *  fn_data - Extra data passed to callback function;
    238  *  must match registered value unless fn is NULL
    239  * Returns:
    240  *  SOC_E_NONE - Success
    241  *  SOC_E_NOT_FOUND - Matching registered routine not found
    242  */
    243 
    244 int
    245 soc_l2_entry_unregister(int unit, soc_l2_entry_cb_fn fn, void *fn_data)
    246 {
    247     l2_entry_data_t *ad = &tr3_l2x_data[unit];
    248     int             i;
    249 
    250     if (fn == NULL) {
    251         ad->cb_count = 0;
    252         return SOC_E_NONE;
    253     }
    254 
    255     for (i = 0; i < ad->cb_count; i++) {
    256         if ((ad->cb[i].fn == fn &&
    257              ad->cb[i].fn_data == fn_data)) {
    258 
    259             for (ad->cb_count--; i < ad->cb_count; i++) {
    260                 sal_memcpy(&ad->cb[i], &ad->cb[i + 1],
    261                            sizeof (l2_entry_cb_entry_t));
    262             }
    263 
    264             return SOC_E_NONE;
    265         }
    266     }
    267 
    268     return SOC_E_NOT_FOUND;
    269 }
    270 
    271 /*
    272  * Function:
    273  *	soc_l2_entry_callback
    274  * Purpose:
    275  *	Routine to execute all callbacks on the list.
    276  * Parameters:
    277  *	unit - unit number.
    278  *	entry_del - deleted or updated entry, NULL if none.
    279  *	entry_add - added or updated entry, NULL if none.
    280  */
    281 
    282 void
    283 soc_l2_entry_callback(int unit, uint32 flags, soc_mem_t mem_type, 
    284                       l2_combo_entry_t *entry_del, l2_combo_entry_t *entry_add)
    285 {
    286     l2_entry_data_t *ad = &tr3_l2x_data[unit];
    287     int        i;
    288     
    289     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    290                 (BSL_META_U(unit,
    291                             "%s %s %s\n"), FUNCTION_NAME(), entry_del ? "DEL" : "",
    292                  entry_add ? "ADD" : ""));
    293     for (i = 0; i < ad->cb_count; i++) {
    294         (*ad->cb[i].fn)(unit, flags, mem_type, entry_del, entry_add, ad->cb[i].fn_data);
    295     }
    296 }
    297 
    298 /*
    299  * Function:
    300  * 	soc_l2x_running
    301  * Purpose:
    302  *	Determine the L2X sync thread running parameters
    303  * Parameters:
    304  *	unit - unit number.
    305  *	flags (OUT) - if non-NULL, receives the current flag settings
    306  *	interval (OUT) - if non-NULL, receives the current pass interval
    307  * Returns:
    308  *   	Boolean; TRUE if L2X sync thread is running
    309  */
    310 
    311 int
    312 soc_tr3_l2x_running(int unit, uint32 *flags, sal_usecs_t *interval)
    313 {
    314     soc_control_t *soc = SOC_CONTROL(unit);
    315 
    316     if (soc->l2x_pid != SAL_THREAD_ERROR) {
    317         if (flags != NULL) {
    318             *flags = soc->l2x_flags;
    319         }
    320         if (interval != NULL) {
    321             *interval = soc->l2x_interval;
    322         }
    323     }
    324 
    325     return(soc->l2x_pid != SAL_THREAD_ERROR);
    326 }
    327 
    328 /* It can only handle delete so far */
    329 int
    330 _soc_tr3_l2x_sync_replace(int unit, _soc_tr3_l2_replace_t *rep_st,
    331                           uint32 flags)
    332 {
    333     soc_control_t *soc = SOC_CONTROL(unit);
    334     uint32 kt, *entry, *match_data, *match_mask;
    335     int index_max, entry_words, idx, i;
    336     soc_memacc_t l21_key_type;
    337     soc_mem_t mem_type;
    338 
    339     if (soc->l2x_pid == SAL_THREAD_ERROR) {
    340         /* thread not running */
    341         return SOC_E_NONE;
    342     }
    343     
    344     /* First work on Internal L2 */
    345     entry = tr3_l2x_data[unit].shadow_tab_int;
    346     if (entry == NULL) {
    347         return SOC_E_NONE;
    348     }
    349 
    350     SOC_IF_ERROR_RETURN
    351         (soc_memacc_init(unit, L2_ENTRY_1m, KEY_TYPEf, &l21_key_type));
    352 
    353     index_max = soc_mem_index_max(unit, L2_ENTRY_1m);
    354     (void)sal_sem_take(soc->l2x_lock, sal_sem_FOREVER);
    355     for (idx = 0; idx <= index_max; ) {
    356         mem_type = L2_ENTRY_1m;
    357         match_data = (uint32 *)&rep_st->match_data1;
    358         match_mask = (uint32 *)&rep_st->match_mask1;
    359         kt = soc_memacc_field32_get(&l21_key_type, entry);
    360         if ((kt == SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE) || 
    361             (kt == SOC_MEM_KEY_L2_ENTRY_2_L2_VFI) ||
    362             (kt == SOC_MEM_KEY_L2_ENTRY_2_L2_TRILL_NONUC_ACCESS)) {
    363             mem_type = L2_ENTRY_2m;
    364             match_data = (uint32 *)&rep_st->match_data2;
    365             match_mask = (uint32 *)&rep_st->match_mask2;
    366         }
    367         entry_words = soc_mem_entry_words(unit, mem_type);
    368         for (i = 0; i < entry_words; i++) {
    369             if ((entry[i] ^ match_data[i]) & match_mask[i]) {
    370                 break;
    371             }
    372         }
    373         if (i != entry_words) {
    374             entry += entry_words;
    375             if (mem_type == L2_ENTRY_1m) {
    376                 idx++;
    377             } else {
    378                 idx += 2;
    379             }
    380             continue;
    381         }
    382         soc_tr3_l2x_sync_delete(unit, mem_type, entry, idx, flags);
    383         if (mem_type == L2_ENTRY_1m) {
    384             idx++;
    385         } else {
    386             idx += 2;
    387         }
    388         entry += entry_words;
    389     }
    390     (void)sal_sem_give(soc->l2x_lock);
    391     
    392     /* Then work on external L2 */
    393     if (!soc_feature(unit, soc_feature_esm_support)) { 
    394         return SOC_E_NONE;
    395     }
    396     /* First work on EXT_L2_ENTRY_1 */
    397     entry = tr3_l2x_data[unit].shadow_tab_ext1;
    398     if (entry == NULL) {
    399         return SOC_E_NONE;
    400     }
    401     index_max = soc_mem_index_max(unit, EXT_L2_ENTRY_1m);    
    402     entry_words = soc_mem_entry_words(unit, EXT_L2_ENTRY_1m);
    403     (void)sal_sem_take(soc->l2x_lock, sal_sem_FOREVER);
    404     for (idx = 0; idx <= index_max; idx++, entry += entry_words) {
    405         match_data = (uint32 *)&rep_st->ext_match_data1;
    406         match_mask = (uint32 *)&rep_st->ext_match_mask1;        
    407         for (i = 0; i < entry_words; i++) {
    408             if ((entry[i] ^ match_data[i]) & match_mask[i]) {
    409                 break;
    410             }
    411         }
    412         if (i != entry_words) {
    413             continue;
    414         }
    415         soc_tr3_l2x_sync_delete(unit, EXT_L2_ENTRY_1m, entry, idx, flags);
    416     }
    417     (void)sal_sem_give(soc->l2x_lock);
    418     
    419     /* Then work on EXT_L2_ENTRY_2 */
    420     entry = tr3_l2x_data[unit].shadow_tab_ext2;
    421     if (entry == NULL) {
    422         return SOC_E_NONE;
    423     }
    424     index_max = soc_mem_index_max(unit, EXT_L2_ENTRY_2m);    
    425     entry_words = soc_mem_entry_words(unit, EXT_L2_ENTRY_2m);
    426     (void)sal_sem_take(soc->l2x_lock, sal_sem_FOREVER);
    427     for (idx = 0; idx <= index_max; idx++, entry += entry_words) {
    428         match_data = (uint32 *)&rep_st->ext_match_data2;
    429         match_mask = (uint32 *)&rep_st->ext_match_mask2;        
    430         for (i = 0; i < entry_words; i++) {
    431             if ((entry[i] ^ match_data[i]) & match_mask[i]) {
    432                 break;
    433             }
    434         }
    435         if (i != entry_words) {
    436             continue;
    437         }
    438         soc_tr3_l2x_sync_delete(unit, EXT_L2_ENTRY_2m, entry, idx, flags);
    439     }
    440     (void)sal_sem_give(soc->l2x_lock);
    441     
    442     return SOC_E_NONE;
    443 }
    444 
    445 /*
    446  * Function:
    447  * 	_soc_tr3_l2x_sync_delete_by
    448  * Purpose:
    449  *	Search all the entries in the shadow table based on the 
    450  *	criteria and mark them as deleted.
    451  * Parameters:
    452  * Returns:
    453  *      SOC_E_XX
    454  */
    455 int
    456 _soc_tr3_l2x_sync_delete_by(int unit, uint32 mod, uint32 port,
    457                             uint16 vid, uint32 tid, int vfi,
    458                             uint32 flags, uint32 search_key)
    459 {
    460     soc_control_t *soc = SOC_CONTROL(unit);
    461     int           rv = SOC_E_NONE, static_bit_val;
    462     int           index, max_index, stl2;
    463     uint32        *entry = NULL;
    464     uint32        port_val, mod_id;
    465     vlan_id_t     vlan_id;
    466 
    467 
    468     if (soc->l2x_pid == SAL_THREAD_ERROR) {
    469         /* thread not running */
    470         return SOC_E_NONE;
    471     }
    472     stl2 = (flags & SOC_L2X_INC_STATIC) ? 1 : 0;
    473     (void)sal_sem_take(soc->l2x_lock, sal_sem_FOREVER);
    474     entry = tr3_l2x_data[unit].shadow_tab_int;
    475     if (!entry) {
    476         goto exit;
    477     }
    478 
    479     max_index = soc_mem_index_max(unit, L2_ENTRY_1m);
    480 
    481     if (search_key == SOC_L2X_PORTMOD_DEL) {
    482         /* First work through L2_ENTRY_1 */
    483         for (index = 0; index < max_index; index++,
    484             entry += tr3_l2x_data[unit].entry_words_int) {
    485             if (!L2X_IS_VALID_ENTRY(unit, L2_ENTRY_1m, 
    486                                     entry, VALIDf)) {
    487                 continue;
    488             }
    489             if (soc_mem_field32_get(unit, L2_ENTRY_1m, entry,
    490                                     L2__DEST_TYPEf) == 1) {
    491                 continue;
    492             }
    493             port_val = soc_mem_field32_get(unit, L2_ENTRY_1m,
    494                                            entry, L2__PORT_NUMf);
    495             mod_id = soc_mem_field32_get(unit, L2_ENTRY_1m,
    496                                          entry, L2__MODULE_IDf);
    497             if ((port != port_val) || (mod != mod_id)) {
    498                 continue;
    499             }
    500             static_bit_val = soc_mem_field32_get(unit, L2_ENTRY_1m,
    501                                                  entry, STATIC_BITf);
    502             if (stl2 || (stl2 == static_bit_val)) {
    503                 soc_tr3_l2x_sync_delete(unit, L2_ENTRY_1m, entry, index, flags);
    504             }
    505         }
    506 
    507         /* Then work through L2_ENTRY_2 */
    508         entry = tr3_l2x_data[unit].shadow_tab_int;
    509         max_index = soc_mem_index_max(unit, L2_ENTRY_2m);
    510         for (index = 0; index < max_index; index+=2,
    511             entry += tr3_l2x_data[unit].entry_words_int * 2) {
    512             if (!L2X_IS_VALID_ENTRY(unit, L2_ENTRY_2m, 
    513                                     entry, VALID_0f)) {
    514                 continue;
    515             }
    516             if (soc_mem_field32_get(unit, L2_ENTRY_2m, entry,
    517                                     L2__DEST_TYPEf) == 1) {
    518                 continue;
    519             }
    520             port_val = soc_mem_field32_get(unit, L2_ENTRY_2m,
    521                                            entry, L2__PORT_NUMf);
    522             mod_id = soc_mem_field32_get(unit, L2_ENTRY_2m,
    523                                          entry, L2__MODULE_IDf);
    524             if ((port != port_val) || (mod != mod_id)) {
    525                 continue;
    526             }
    527             static_bit_val = soc_mem_field32_get(unit, L2_ENTRY_2m,
    528                                                  entry, STATIC_BITf);
    529             if (stl2 || (stl2 == static_bit_val)) {
    530                 soc_tr3_l2x_sync_delete(unit, L2_ENTRY_2m, entry, index, flags);
    531             }
    532         }
    533 
    534         if (soc_feature(unit, soc_feature_esm_support)) {
    535             /* First work through EXT_L2_ENTRY_1 */
    536             max_index = soc_mem_index_max(unit, EXT_L2_ENTRY_1m);
    537             entry = tr3_l2x_data[unit].shadow_tab_ext1;
    538             if (entry) {
    539                 for (index = 0; index < max_index; index++,
    540                     entry += tr3_l2x_data[unit].entry_words_ext1) {
    541                     if (L2X_IS_VALID_ENTRY(unit, EXT_L2_ENTRY_1m, 
    542                                             entry, FREEf)) {
    543                         continue;
    544                     }
    545                     if (soc_mem_field32_get(unit, EXT_L2_ENTRY_1m, entry,
    546                                             DEST_TYPEf) == 1) {
    547                         continue;
    548                     }
    549                     port_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_1m,
    550                                                    entry, PORT_NUMf);
    551                     mod_id = soc_mem_field32_get(unit, EXT_L2_ENTRY_1m,
    552                                                  entry, MODULE_IDf);
    553                     if ((port != port_val) || (mod != mod_id)) {
    554                         continue;
    555                     }
    556                     static_bit_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_1m,
    557                                                          entry, STATIC_BITf);
    558                     if (stl2 || (stl2 == static_bit_val)) {
    559                         soc_tr3_l2x_sync_delete(unit, EXT_L2_ENTRY_1m, entry, 
    560                                                 index, flags);
    561                     }
    562                 }
    563             }
    564             
    565             /* Then work through EXT_L2_ENTRY_2 */
    566             max_index = soc_mem_index_max(unit, EXT_L2_ENTRY_2m);
    567             entry = tr3_l2x_data[unit].shadow_tab_ext2;
    568             if (entry) {
    569                 for (index = 0; index < max_index; index++,
    570                     entry += tr3_l2x_data[unit].entry_words_ext2) {
    571                     if (L2X_IS_VALID_ENTRY(unit, EXT_L2_ENTRY_2m, 
    572                                             entry, FREEf)) {
    573                         continue;
    574                     }
    575                     if (soc_mem_field32_get(unit, EXT_L2_ENTRY_2m, entry,
    576                                             DEST_TYPEf) == 1) {
    577                         continue;
    578                     }
    579                     port_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_2m,
    580                                                    entry, PORT_NUMf);
    581                     mod_id = soc_mem_field32_get(unit, EXT_L2_ENTRY_2m,
    582                                                  entry, MODULE_IDf);
    583                     if ((port != port_val) || (mod != mod_id)) {
    584                         continue;
    585                     }
    586                 
    587                     static_bit_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_2m,
    588                                                          entry, STATIC_BITf);
    589                     if (stl2 || (stl2 == static_bit_val)) {
    590                         soc_tr3_l2x_sync_delete(unit, EXT_L2_ENTRY_2m, entry, 
    591                                                 index, flags);
    592                     }
    593                 }
    594             }
    595         }
    596         goto exit;
    597     }
    598 
    599     if (search_key == SOC_L2X_VLAN_DEL) {
    600         /* First work through L2_ENTRY_1 */
    601         for (index = 0; index < max_index; index++,
    602             entry += tr3_l2x_data[unit].entry_words_int) {
    603             if (!L2X_IS_VALID_ENTRY(unit, L2_ENTRY_1m, 
    604                                     entry, VALIDf)) {
    605                 continue;
    606             }
    607             vlan_id = soc_mem_field32_get(unit, L2_ENTRY_1m,
    608                                           entry, L2__VLAN_IDf);
    609             if (vid != vlan_id) {
    610                 continue;
    611             }
    612             static_bit_val = soc_mem_field32_get(unit, L2_ENTRY_1m,
    613                                                  entry, STATIC_BITf);
    614             if (stl2 || (stl2 == static_bit_val)) {
    615                 soc_tr3_l2x_sync_delete(unit, L2_ENTRY_1m, entry, index, flags);
    616             }
    617         }
    618 
    619         /* Then work through L2_ENTRY_2 */
    620         entry = tr3_l2x_data[unit].shadow_tab_int;
    621         max_index = soc_mem_index_max(unit, L2_ENTRY_2m);
    622         for (index = 0; index < max_index; index+=2,
    623             entry += tr3_l2x_data[unit].entry_words_int * 2) {
    624             if (!L2X_IS_VALID_ENTRY(unit, L2_ENTRY_2m, 
    625                                     entry, VALID_0f)) {
    626                 continue;
    627             }
    628             vlan_id = soc_mem_field32_get(unit, L2_ENTRY_2m,
    629                                           entry, L2__VLAN_IDf);
    630             if (vid != vlan_id) {
    631                 continue;
    632             }
    633             static_bit_val = soc_mem_field32_get(unit, L2_ENTRY_2m,
    634                                                  entry, STATIC_BITf);
    635             if (stl2 || (stl2 == static_bit_val)) {
    636                 soc_tr3_l2x_sync_delete(unit, L2_ENTRY_2m, entry, index, flags);
    637             }
    638         }
    639 
    640         if (soc_feature(unit, soc_feature_esm_support)) {
    641             /* First work through EXT_L2_ENTRY_1 */
    642             max_index = soc_mem_index_max(unit, EXT_L2_ENTRY_1m);
    643             entry = tr3_l2x_data[unit].shadow_tab_ext1;
    644             if (entry) {
    645                 for (index = 0; index < max_index; index++,
    646                     entry += tr3_l2x_data[unit].entry_words_ext1) {
    647                     if (L2X_IS_VALID_ENTRY(unit, EXT_L2_ENTRY_1m, 
    648                                             entry, FREEf)) {
    649                         continue;
    650                     }
    651                     vlan_id = soc_mem_field32_get(unit, EXT_L2_ENTRY_1m,
    652                                                   entry, VLAN_IDf);
    653                     if (vid != vlan_id) {
    654                         continue;
    655                     }
    656                     static_bit_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_1m,
    657                                                          entry, STATIC_BITf);
    658                     if (stl2 || (stl2 == static_bit_val)) {
    659                         soc_tr3_l2x_sync_delete(unit, EXT_L2_ENTRY_1m, entry, 
    660                                                 index, flags);
    661                     }
    662                 }
    663             }
    664             
    665             /* Then work through EXT_L2_ENTRY_2 */
    666             max_index = soc_mem_index_max(unit, EXT_L2_ENTRY_2m);
    667             entry = tr3_l2x_data[unit].shadow_tab_ext2;
    668             if (entry) {
    669                 for (index = 0; index < max_index; index++,
    670                     entry += tr3_l2x_data[unit].entry_words_ext2) {
    671                     if (L2X_IS_VALID_ENTRY(unit, EXT_L2_ENTRY_2m, 
    672                                             entry, FREEf)) {
    673                         continue;
    674                     }
    675                     vlan_id = soc_mem_field32_get(unit, EXT_L2_ENTRY_2m,
    676                                                   entry, VLAN_IDf);
    677                     if (vid != vlan_id) {
    678                         continue;
    679                     }
    680                     static_bit_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_2m,
    681                                                          entry, STATIC_BITf);
    682                     if (stl2 || (stl2 == static_bit_val)) {
    683                         soc_tr3_l2x_sync_delete(unit, EXT_L2_ENTRY_2m, entry, 
    684                                                 index, flags);
    685                     }
    686                 }
    687             }
    688         }
    689         goto exit;
    690     }
    691 
    692     if (search_key == SOC_L2X_VFI_DEL) {
    693         int vfi_id;
    694         /* First work through L2_ENTRY_1 */
    695         for (index = 0; index < max_index; index++,
    696             entry += tr3_l2x_data[unit].entry_words_int) {
    697             if (!L2X_IS_VALID_ENTRY(unit, L2_ENTRY_1m,
    698                                     entry, VALIDf)) {
    699                 continue;
    700             }
    701             vfi_id = soc_mem_field32_get(unit, L2_ENTRY_1m,
    702                                          entry, L2__VFIf);
    703             if (vfi != vfi_id) {
    704                 continue;
    705             }
    706             static_bit_val = soc_mem_field32_get(unit, L2_ENTRY_1m,
    707                                                  entry, STATIC_BITf);
    708             if (stl2 || (stl2 == static_bit_val)) {
    709                 soc_tr3_l2x_sync_delete(unit, L2_ENTRY_1m, entry, index, flags);
    710             }
    711         }
    712 
    713         /* Then work through L2_ENTRY_2 */
    714         entry = tr3_l2x_data[unit].shadow_tab_int;
    715         max_index = soc_mem_index_max(unit, L2_ENTRY_2m);
    716         for (index = 0; index < max_index; index+=2,
    717             entry += tr3_l2x_data[unit].entry_words_int * 2) {
    718             if (!L2X_IS_VALID_ENTRY(unit, L2_ENTRY_2m,
    719                                     entry, VALID_0f)) {
    720                 continue;
    721             }
    722             vfi_id = soc_mem_field32_get(unit, L2_ENTRY_2m,
    723                                          entry, L2__VFIf);
    724             if (vfi != vfi_id) {
    725                 continue;
    726             }
    727             static_bit_val = soc_mem_field32_get(unit, L2_ENTRY_2m,
    728                                                  entry, STATIC_BITf);
    729             if (stl2 || (stl2 == static_bit_val)) {
    730                 soc_tr3_l2x_sync_delete(unit, L2_ENTRY_2m, entry, index, flags);
    731             }
    732         }
    733 
    734         if (soc_feature(unit, soc_feature_esm_support)) {
    735             /* First work through EXT_L2_ENTRY_1 */
    736             max_index = soc_mem_index_max(unit, EXT_L2_ENTRY_1m);
    737             entry = tr3_l2x_data[unit].shadow_tab_ext1;
    738             if (entry) {
    739                 for (index = 0; index < max_index; index++,
    740                     entry += tr3_l2x_data[unit].entry_words_ext1) {
    741                     if (L2X_IS_VALID_ENTRY(unit, EXT_L2_ENTRY_1m, 
    742                                             entry, FREEf)) {
    743                         continue;
    744                     }
    745                     vfi_id = soc_mem_field32_get(unit, EXT_L2_ENTRY_1m,
    746                                                  entry, VFIf);
    747                     if (vfi != vfi_id) {
    748                         continue;
    749                     }
    750                     static_bit_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_1m,
    751                                                          entry, STATIC_BITf);
    752                     if (stl2 || (stl2 == static_bit_val)) {
    753                         soc_tr3_l2x_sync_delete(unit, EXT_L2_ENTRY_1m, entry, 
    754                                                 index, flags);
    755                     }
    756                 }
    757             }
    758             
    759             /* Then work through EXT_L2_ENTRY_2 */
    760             max_index = soc_mem_index_max(unit, EXT_L2_ENTRY_2m);
    761             entry = tr3_l2x_data[unit].shadow_tab_ext2;
    762             if (entry) {
    763                 for (index = 0; index < max_index; index++,
    764                     entry += tr3_l2x_data[unit].entry_words_ext2) {
    765                     if (L2X_IS_VALID_ENTRY(unit, EXT_L2_ENTRY_2m, 
    766                                             entry, FREEf)) {
    767                         continue;
    768                     }
    769                     vfi_id = soc_mem_field32_get(unit, EXT_L2_ENTRY_2m,
    770                                                  entry, VFIf);
    771                     if (vfi != vfi_id) {
    772                         continue;
    773                     }
    774                     static_bit_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_2m,
    775                                                          entry, STATIC_BITf);
    776                     if (stl2 || (stl2 == static_bit_val)) {
    777                         soc_tr3_l2x_sync_delete(unit, EXT_L2_ENTRY_2m, entry, 
    778                                                 index, flags);
    779                     }
    780                 }
    781             }
    782         }
    783         goto exit;
    784     }
    785 
    786     if (search_key == SOC_L2X_PORTMOD_VLAN_DEL) {
    787         /* First work through L2_ENTRY_1 */
    788         for (index = 0; index < max_index; index++,
    789             entry += tr3_l2x_data[unit].entry_words_int) {
    790             if (!L2X_IS_VALID_ENTRY(unit, L2_ENTRY_1m, 
    791                                     entry, VALIDf)) {
    792                 continue;
    793             }
    794             if (soc_mem_field32_get(unit, L2_ENTRY_1m, entry,
    795                                     L2__DEST_TYPEf) == 1) {
    796                 continue;
    797             }
    798             port_val = soc_mem_field32_get(unit, L2_ENTRY_1m,
    799                                            entry, L2__PORT_NUMf);
    800             mod_id = soc_mem_field32_get(unit, L2_ENTRY_1m,
    801                                          entry, L2__MODULE_IDf);
    802             vlan_id = soc_mem_field32_get(unit, L2_ENTRY_1m,
    803                                           entry, L2__VLAN_IDf);
    804             if ((vid != vlan_id) ||(port != port_val) ||(mod != mod_id)) {
    805                 continue;
    806             }
    807             static_bit_val = soc_mem_field32_get(unit, L2_ENTRY_1m,
    808                                                  entry, STATIC_BITf);
    809             if (stl2 || (stl2 == static_bit_val)) {
    810                 soc_tr3_l2x_sync_delete(unit, L2_ENTRY_1m, entry, index, flags);
    811             }
    812         }
    813 
    814         /* Then work through L2_ENTRY_2 */
    815         entry = tr3_l2x_data[unit].shadow_tab_int;
    816         max_index = soc_mem_index_max(unit, L2_ENTRY_2m);
    817         for (index = 0; index < max_index; index+=2,
    818             entry += tr3_l2x_data[unit].entry_words_int * 2) {
    819             if (!L2X_IS_VALID_ENTRY(unit, L2_ENTRY_2m, 
    820                                     entry, VALID_0f)) {
    821                 continue;
    822             }
    823             if (soc_mem_field32_get(unit, L2_ENTRY_2m, entry,
    824                                     L2__DEST_TYPEf) == 1) {
    825                 continue;
    826             }
    827             port_val = soc_mem_field32_get(unit, L2_ENTRY_2m,
    828                                            entry, L2__PORT_NUMf);
    829             mod_id = soc_mem_field32_get(unit, L2_ENTRY_2m,
    830                                          entry, L2__MODULE_IDf);
    831             vlan_id = soc_mem_field32_get(unit, L2_ENTRY_2m,
    832                                           entry, L2__VLAN_IDf);
    833             if ((vid != vlan_id) ||(port != port_val) ||(mod != mod_id)) {
    834                 continue;
    835             }
    836             static_bit_val = soc_mem_field32_get(unit, L2_ENTRY_2m,
    837                                                  entry, STATIC_BITf);
    838             if (stl2 || (stl2 == static_bit_val)) {
    839                 soc_tr3_l2x_sync_delete(unit, L2_ENTRY_2m, entry, index, flags);
    840             }
    841         }
    842         
    843         if (soc_feature(unit, soc_feature_esm_support)) {
    844             /* First work through EXT_L2_ENTRY_1 */
    845             max_index = soc_mem_index_max(unit, EXT_L2_ENTRY_1m);
    846             entry = tr3_l2x_data[unit].shadow_tab_ext1;
    847             if (entry) {
    848                 for (index = 0; index < max_index; index++,
    849                     entry += tr3_l2x_data[unit].entry_words_ext1) {
    850                     if (L2X_IS_VALID_ENTRY(unit, EXT_L2_ENTRY_1m, 
    851                                             entry, FREEf)) {
    852                         continue;
    853                     }
    854                     port_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_1m,
    855                                                    entry, PORT_NUMf);
    856                     mod_id = soc_mem_field32_get(unit, EXT_L2_ENTRY_1m,
    857                                                  entry, MODULE_IDf);
    858                     vlan_id = soc_mem_field32_get(unit, EXT_L2_ENTRY_1m,
    859                                                   entry, VLAN_IDf);
    860                     if ((vid != vlan_id) ||(port != port_val) ||(mod != mod_id)) {
    861                         continue;
    862                     }
    863                     static_bit_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_1m,
    864                                                          entry, STATIC_BITf);
    865                     if (stl2 || (stl2 == static_bit_val)) {
    866                         soc_tr3_l2x_sync_delete(unit, EXT_L2_ENTRY_1m, entry, 
    867                                                 index, flags);
    868                     }
    869                 }
    870             }
    871             
    872             /* Then work through EXT_L2_ENTRY_2 */
    873             max_index = soc_mem_index_max(unit, EXT_L2_ENTRY_2m);
    874             entry = tr3_l2x_data[unit].shadow_tab_ext2;
    875             if (entry) {
    876                 for (index = 0; index < max_index; index++,
    877                     entry += tr3_l2x_data[unit].entry_words_ext2) {
    878                     if (L2X_IS_VALID_ENTRY(unit, EXT_L2_ENTRY_2m, 
    879                                             entry, FREEf)) {
    880                         continue;
    881                     }
    882                     port_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_2m,
    883                                                    entry, PORT_NUMf);
    884                     mod_id = soc_mem_field32_get(unit, EXT_L2_ENTRY_2m,
    885                                                  entry, MODULE_IDf);
    886                     vlan_id = soc_mem_field32_get(unit, EXT_L2_ENTRY_2m,
    887                                                   entry, VLAN_IDf);
    888                     if ((vid != vlan_id) ||(port != port_val) ||(mod != mod_id)) {
    889                         continue;
    890                     }
    891                     static_bit_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_2m,
    892                                                          entry, STATIC_BITf);
    893                     if (stl2 || (stl2 == static_bit_val)) {
    894                         soc_tr3_l2x_sync_delete(unit, EXT_L2_ENTRY_2m, entry, 
    895                                                 index, flags);
    896                     }
    897                 }
    898             }
    899         }
    900         goto exit;
    901     }
    902 
    903     if ((search_key == SOC_L2X_TRUNK_DEL) || 
    904         (search_key == SOC_L2X_TRUNK_VLAN_DEL)) {
    905         /* First work through L2_ENTRY_1 */
    906         for (index = 0; index < max_index; index++,
    907             entry += tr3_l2x_data[unit].entry_words_int) {
    908             if (!L2X_IS_VALID_ENTRY(unit, L2_ENTRY_1m, 
    909                                     entry, VALIDf)) {
    910                 continue;
    911             }
    912             if ((soc_mem_field32_get(unit, L2_ENTRY_1m,
    913                                      entry, L2__DEST_TYPEf) != 1) ||
    914                 (soc_mem_field32_get(unit, L2_ENTRY_1m,
    915                                      entry, L2__TGIDf) != tid)) {
    916                 continue;
    917             }
    918             if ((search_key == SOC_L2X_TRUNK_VLAN_DEL) && 
    919                 (vid != soc_mem_field32_get(unit, L2_ENTRY_1m,
    920                                             entry, L2__VLAN_IDf))) {
    921                 continue;
    922             }
    923             static_bit_val = soc_mem_field32_get(unit, L2_ENTRY_1m,
    924                                                  entry, STATIC_BITf);
    925             if (stl2 || (stl2 == static_bit_val)) {
    926                 soc_tr3_l2x_sync_delete(unit, L2_ENTRY_1m, entry, index, flags);
    927             }
    928         }
    929 
    930         /* Then work through L2_ENTRY_2 */
    931         entry = tr3_l2x_data[unit].shadow_tab_int;
    932         max_index = soc_mem_index_max(unit, L2_ENTRY_2m);
    933         for (index = 0; index < max_index; index+=2,
    934             entry += tr3_l2x_data[unit].entry_words_int * 2) {
    935             if (!L2X_IS_VALID_ENTRY(unit, L2_ENTRY_2m, 
    936                                     entry, VALID_0f)) {
    937                 continue;
    938             }
    939             if ((soc_mem_field32_get(unit, L2_ENTRY_2m,
    940                                      entry, L2__DEST_TYPEf) != 1) ||
    941                 (soc_mem_field32_get(unit, L2_ENTRY_2m,
    942                                      entry, L2__TGIDf) != tid)) {
    943                 continue;
    944             }
    945             if ((search_key == SOC_L2X_TRUNK_VLAN_DEL) && 
    946                 (vid != soc_mem_field32_get(unit, L2_ENTRY_2m,
    947                                             entry, L2__VLAN_IDf))) {
    948                 continue;
    949             }
    950             static_bit_val = soc_mem_field32_get(unit, L2_ENTRY_2m,
    951                                                  entry, STATIC_BITf);
    952             if (stl2 || (stl2 == static_bit_val)) {
    953                 soc_tr3_l2x_sync_delete(unit, L2_ENTRY_2m, entry, index, flags);
    954             }
    955         }
    956         
    957         if (soc_feature(unit, soc_feature_esm_support)) {
    958             /* First work through EXT_L2_ENTRY_1 */
    959             max_index = soc_mem_index_max(unit, EXT_L2_ENTRY_1m);
    960             entry = tr3_l2x_data[unit].shadow_tab_ext1;
    961             if (entry) {
    962                 for (index = 0; index < max_index; index++,
    963                     entry += tr3_l2x_data[unit].entry_words_ext1) {
    964                     if (L2X_IS_VALID_ENTRY(unit, EXT_L2_ENTRY_1m, 
    965                                             entry, FREEf)) {
    966                         continue;
    967                     }
    968                     if ((soc_mem_field32_get(unit, EXT_L2_ENTRY_1m,
    969                                              entry, DEST_TYPEf) != 1) ||
    970                         (soc_mem_field32_get(unit, EXT_L2_ENTRY_1m,
    971                                              entry, TGIDf) != tid)) {
    972                         continue;
    973                     }
    974                     if ((search_key == SOC_L2X_TRUNK_VLAN_DEL) && 
    975                         (vid != soc_mem_field32_get(unit, EXT_L2_ENTRY_1m,
    976                                                     entry, VLAN_IDf))) {
    977                         continue;
    978                     }
    979                     static_bit_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_1m,
    980                                                          entry, STATIC_BITf);
    981                     if (stl2 || (stl2 == static_bit_val)) {
    982                         soc_tr3_l2x_sync_delete(unit, EXT_L2_ENTRY_1m, entry, 
    983                                                 index, flags);
    984                     }
    985                 }
    986             }
    987             
    988             /* Then work through EXT_L2_ENTRY_2 */
    989             max_index = soc_mem_index_max(unit, EXT_L2_ENTRY_2m);
    990             entry = tr3_l2x_data[unit].shadow_tab_ext2;
    991             if (entry) {
    992                 for (index = 0; index < max_index; index++,
    993                     entry += tr3_l2x_data[unit].entry_words_ext2) {
    994                     if (L2X_IS_VALID_ENTRY(unit, EXT_L2_ENTRY_2m, 
    995                                             entry, FREEf)) {
    996                         continue;
    997                     }
    998                     if ((soc_mem_field32_get(unit, EXT_L2_ENTRY_2m,
    999                                              entry, DEST_TYPEf) != 1) ||
   1000                         (soc_mem_field32_get(unit, EXT_L2_ENTRY_2m,
   1001                                              entry, TGIDf) != tid)) {
   1002                         continue;
   1003                     }
   1004                     if ((search_key == SOC_L2X_TRUNK_VLAN_DEL) && 
   1005                         (vid != soc_mem_field32_get(unit, EXT_L2_ENTRY_2m,
   1006                                                     entry, VLAN_IDf))) {
   1007                         continue;
   1008                     }
   1009                     static_bit_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_2m,
   1010                                                          entry, STATIC_BITf);
   1011                     if (stl2 || (stl2 == static_bit_val)) {
   1012                         soc_tr3_l2x_sync_delete(unit, EXT_L2_ENTRY_2m, entry, 
   1013                                                 index, flags);
   1014                     }
   1015                 }
   1016             }
   1017         }
   1018         goto exit;
   1019     }
   1020 
   1021     rv = SOC_E_PARAM;
   1022 
   1023 exit:
   1024     (void)sal_sem_give(soc->l2x_lock);
   1025     return rv;
   1026 }
   1027 
   1028 /*
   1029  * Function:
   1030  * 	soc_tr3_l2x_sync_delete
   1031  * Purpose:
   1032  *	sync the SW shadow copy for the deleted entry from HW.
   1033  * Parameters:
   1034  *	unit - unit number.
   1035  *	del_entry - entry deleted from the HW l2X memory
   1036  * Returns:
   1037  *      SOC_E_XX
   1038  */
   1039 
   1040 int
   1041 soc_tr3_l2x_sync_delete(int unit, soc_mem_t mem, uint32 *del_entry, int index, 
   1042                         uint32 flags)
   1043 {
   1044     soc_control_t *soc = SOC_CONTROL(unit);
   1045     int           max_index;
   1046     uint32        *tab_p, kt;
   1047     soc_mem_t     mem_type;   
   1048 
   1049     LOG_INFO(BSL_LS_SOC_ARL,
   1050              (BSL_META_U(unit,
   1051                          "soc_tr3_l2x_sync_delete: unit=%d index=%d\n"),
   1052                          unit, index));
   1053 
   1054     if (soc->l2x_pid == SAL_THREAD_ERROR) {
   1055         /* thread not running */
   1056         return SOC_E_NONE;
   1057     }
   1058 
   1059     if (!tr3_l2x_data[unit].enabled) {
   1060         return SOC_E_NONE;
   1061     }
   1062     
   1063     if (mem == L2_ENTRY_1m || mem == L2_ENTRY_2m) {
   1064         /* Determine entry type/size */
   1065         mem_type = L2_ENTRY_1m;
   1066         kt = soc_mem_field32_get(unit, L2_ENTRY_1m, del_entry, KEY_TYPEf);
   1067         if ((kt == SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE) || 
   1068             (kt == SOC_MEM_KEY_L2_ENTRY_2_L2_VFI) ||
   1069             (kt == SOC_MEM_KEY_L2_ENTRY_2_L2_TRILL_NONUC_ACCESS)) {
   1070             mem_type = L2_ENTRY_2m;
   1071         }
   1072         if (mem_type == L2_ENTRY_1m) {
   1073             max_index = soc_mem_index_max(unit, L2_ENTRY_1m);
   1074         } else {
   1075             max_index = soc_mem_index_max(unit, L2_ENTRY_2m);
   1076         }
   1077         if (index > max_index) {
   1078             return SOC_E_PARAM;
   1079         }
   1080         
   1081         /*
   1082          * validate that the entry in the shadow copy is same as the entry
   1083          * deleted.
   1084          */
   1085         if (mem_type == L2_ENTRY_1m) {
   1086             tab_p = tr3_l2x_data[unit].shadow_tab_int + 
   1087                     (index * tr3_l2x_data[unit].entry_words_int);
   1088         } else {
   1089             tab_p = tr3_l2x_data[unit].shadow_tab_int + 
   1090                     (index * tr3_l2x_data[unit].entry_words_int * 2);
   1091         }    
   1092         if (L2X_ENTRY_EQL(unit, del_entry, tab_p, 0)) {
   1093             L2X_ENTRY_DELETED_SET(unit, index);
   1094             /* Bitmap that indicates to suppress callback */
   1095             if ((flags & SOC_L2X_NO_CALLBACKS)) {
   1096                 L2X_ENTRY_CALLBACK_SET(unit, index);
   1097             }
   1098         }
   1099     } else if (mem == EXT_L2_ENTRY_1m) {
   1100         if (index > soc_mem_index_max(unit, EXT_L2_ENTRY_1m)) {
   1101             return SOC_E_PARAM;
   1102         }        
   1103         /*
   1104          * validate that the entry in the shadow copy is same as the entry
   1105          * deleted.
   1106          */
   1107         tab_p = tr3_l2x_data[unit].shadow_tab_ext1 + 
   1108                     (index * tr3_l2x_data[unit].entry_words_ext1);
   1109         if (EXT_L2X_1_ENTRY_EQL(unit, del_entry, tab_p, 0)) {
   1110             EXT_L2X_1_ENTRY_DELETED_SET(unit, index);
   1111             /* Bitmap that indicates to suppress callback */
   1112             if ((flags & SOC_L2X_NO_CALLBACKS)) {
   1113                 EXT_L2X_1_ENTRY_CALLBACK_SET(unit, index);
   1114             }
   1115         }
   1116     } else if (mem == EXT_L2_ENTRY_2m) {
   1117         if (index > soc_mem_index_max(unit, EXT_L2_ENTRY_2m)) {
   1118             return SOC_E_PARAM;
   1119         }        
   1120         /*
   1121          * validate that the entry in the shadow copy is same as the entry
   1122          * deleted.
   1123          */
   1124         tab_p = tr3_l2x_data[unit].shadow_tab_ext2 + 
   1125                     (index * tr3_l2x_data[unit].entry_words_ext2);
   1126         if (EXT_L2X_2_ENTRY_EQL(unit, del_entry, tab_p, 0)) {
   1127             EXT_L2X_2_ENTRY_DELETED_SET(unit, index);
   1128             /* Bitmap that indicates to suppress callback */
   1129             if ((flags & SOC_L2X_NO_CALLBACKS)) {
   1130                 EXT_L2X_2_ENTRY_CALLBACK_SET(unit, index);
   1131             }
   1132         }
   1133     } else {
   1134         return SOC_E_PARAM;
   1135     }
   1136     return SOC_E_NONE;
   1137 }
   1138 
   1139 /*
   1140  * Function:
   1141  * 	soc_tr3_l2x_stop
   1142  * Purpose:
   1143  *   	Stop L2X-related thread
   1144  * Parameters:
   1145  *	unit - unit number.
   1146  * Returns:
   1147  *	SOC_E_XXX
   1148  */
   1149 
   1150 int
   1151 soc_tr3_l2x_stop(int unit)
   1152 {
   1153     soc_control_t *soc = SOC_CONTROL(unit);
   1154     int           rv = SOC_E_NONE;
   1155     soc_timeout_t to;
   1156 #if defined(BCM_XGS3_SWITCH_SUPPORT) && defined(BCM_CMICM_SUPPORT)
   1157     int           mode;
   1158 #endif
   1159 
   1160     LOG_INFO(BSL_LS_SOC_ARL,
   1161              (BSL_META_U(unit,
   1162                          "soc_tr3_l2x_stop: unit=%d\n"), unit));
   1163 
   1164     tr3_l2x_data[unit].enabled = 0;
   1165     SOC_CONTROL_LOCK(unit);
   1166     soc->l2x_interval = 0;  /* Request exit */
   1167     SOC_CONTROL_UNLOCK(unit);
   1168 
   1169     if (soc->l2x_pid != SAL_THREAD_ERROR) {
   1170         /* Wake up thread so it will check the exit flag */
   1171 #if defined(BCM_XGS3_SWITCH_SUPPORT) && defined(BCM_CMICM_SUPPORT)
   1172         mode = soc_property_get(unit, spn_L2XMSG_MODE, L2MODE_POLL);
   1173         if (soc_feature(unit, soc_feature_l2_modfifo) &&
   1174             (mode == L2MODE_FIFO)) {
   1175             _soc_l2mod_stop(unit);
   1176         } else
   1177 #endif
   1178         {
   1179             sal_sem_give(soc->l2x_notify);
   1180         }
   1181 
   1182         /* Give thread a few seconds to wake up and exit */
   1183         if (SAL_BOOT_SIMULATION) {
   1184             soc_timeout_init(&to, 30 * 1000000, 0);
   1185         } else {
   1186             soc_timeout_init(&to, 10 * 1000000, 0);
   1187         }
   1188 
   1189         while (soc->l2x_pid != SAL_THREAD_ERROR) {
   1190             if (soc_timeout_check(&to)) {
   1191                 LOG_ERROR(BSL_LS_SOC_L2,
   1192                           (BSL_META_U(unit,
   1193                                       "soc_tr3_l2x_stop: thread will not exit\n")));
   1194                 rv = SOC_E_INTERNAL;
   1195                 break;
   1196             }
   1197         }
   1198     }
   1199 
   1200     return rv;
   1201 }
   1202 
   1203 /*
   1204  * Function:
   1205  * 	soc_tr3_l2x_start
   1206  * Purpose:
   1207  *   	Initialize shadow table and start L2X thread to maintain it
   1208  * Parameters:
   1209  *	unit - unit number.
   1210  *	flags - SOC_L2X_FLAG_xxx
   1211  *	interval - time between resynchronization passes
   1212  * Returns:
   1213  *	SOC_E_MEMORY if can't create thread.
   1214  */
   1215 
   1216 int
   1217 soc_tr3_l2x_start(int unit, uint32 flags, sal_usecs_t interval)
   1218 {
   1219     soc_control_t *soc = SOC_CONTROL(unit);
   1220     int           pri;
   1221 #if defined(BCM_XGS3_SWITCH_SUPPORT) && defined(BCM_CMICM_SUPPORT)
   1222     int           mode;
   1223 #endif
   1224 
   1225     LOG_INFO(BSL_LS_SOC_ARL,
   1226              (BSL_META_U(unit,
   1227                          "soc_tr3_l2x_start: unit=%d flags=0x%x interval=%d\n"),
   1228               unit, flags, interval));
   1229 
   1230     if (!soc_feature(unit, soc_feature_arl_hashed)) {
   1231         return SOC_E_UNAVAIL;
   1232     }
   1233 
   1234     if (soc->l2x_interval != 0) {
   1235         SOC_IF_ERROR_RETURN(soc_tr3_l2x_stop(unit));
   1236     }
   1237 
   1238     sal_snprintf(soc->l2x_name, sizeof (soc->l2x_name),
   1239                  "bcmL2X.%d", unit);
   1240 
   1241     if (soc->l2x_pid == SAL_THREAD_ERROR) {
   1242         pri = soc_property_get(unit, spn_L2XMSG_THREAD_PRI, 50);
   1243         soc->l2x_age_hitsa_only = soc_property_get(unit,
   1244                                                    spn_L2X_AGE_ONLY_ON_HITSA,
   1245                                                    0);
   1246 #if defined(BCM_XGS3_SWITCH_SUPPORT) && defined(BCM_CMICM_SUPPORT)
   1247         mode = soc_property_get(unit, spn_L2XMSG_MODE, L2MODE_POLL);
   1248 
   1249         if (mode == L2MODE_FIFO) {
   1250 
   1251             SOC_CONTROL_LOCK(unit);
   1252             soc->l2x_mode = mode;
   1253             soc->l2x_flags = flags;
   1254             soc->l2x_interval = interval;
   1255     
   1256             if (interval == 0) {
   1257                 SOC_CONTROL_UNLOCK(unit);
   1258                 return SOC_E_NONE;
   1259             }
   1260             _soc_l2mod_start(unit, flags, interval);
   1261             SOC_CONTROL_UNLOCK(unit);
   1262             /* For 'FIFO' mode, set the 'enabled' to '0',
   1263                to indicate NO L2 data store. */
   1264             tr3_l2x_data[unit].enabled = 0;
   1265         } else
   1266 #endif
   1267         {
   1268             SOC_CONTROL_LOCK(unit);
   1269             soc->l2x_mode = L2MODE_POLL;
   1270             soc->l2x_flags = flags;
   1271             soc->l2x_interval = interval;
   1272 
   1273             if (interval == 0) {
   1274                 SOC_CONTROL_UNLOCK(unit);
   1275                 return SOC_E_NONE;
   1276             }
   1277             soc->l2x_pid = sal_thread_create(soc->l2x_name,
   1278                                              SAL_THREAD_STKSZ,
   1279                                              pri,
   1280                                              _soc_tr3_l2x_thread,
   1281                                              INT_TO_PTR(unit));
   1282             if (soc->l2x_pid == SAL_THREAD_ERROR) {
   1283                 LOG_ERROR(BSL_LS_SOC_L2,
   1284                           (BSL_META_U(unit,
   1285                                       "soc_tr3_l2x_start: Could not start L2X thread\n")));
   1286                 SOC_CONTROL_UNLOCK(unit);
   1287                 return SOC_E_MEMORY;
   1288             }
   1289             SOC_CONTROL_UNLOCK(unit);
   1290         }
   1291     }
   1292 
   1293     return SOC_E_NONE;
   1294 }
   1295 
   1296 /*
   1297  * Function:
   1298  *	_soc_l2x_sync_bucket
   1299  * Purpose:
   1300  *	Compare the old contents of a hash bucket to the
   1301  *	next contents, make any ARL callbacks that are necessary,
   1302  *	and sync that bucket in the shadow table.
   1303  * Parameters:
   1304  *	unit - StrataSwitch unit #
   1305  *	old_bucket - Previous bucket contents (SOC_TR3_L2X_BUCKET_SIZE entries)
   1306  *	new_bucket - New bucket contents (SOC_TR3_L2X_BUCKET_SIZE entries)
   1307  *	shadow_hit_bits - perform the notify callback even if
   1308  *			only hit bits change.
   1309  *	bucket_index - start index of bucket within chunk
   1310  *	p_chunk_del_map - pointer to chunk's delete map
   1311  * Notes:
   1312  *	It's necessary to process deletions first, then insertions.
   1313  *	If an entry moves within the hash bucket, or some field such
   1314  *	as PORT changes, the application first receives a callback
   1315  *	for a deletion, and then for an insertion.
   1316  */
   1317 
   1318 STATIC void
   1319 _soc_tr3_l2x_sync_bucket(int unit, uint32 *old_bucket, uint32 *new_bucket,
   1320                          uint8 shadow_hit_bits, int bucket_index,
   1321                          SHR_BITDCL *p_chunk_del_map, 
   1322                          SHR_BITDCL *p_chunk_cb_map)
   1323 {
   1324     int       io, in, delete_marked, callback_suppress;
   1325     uint32    *old_p, *old_ptr, *new_p, *new_ptr;
   1326     uint32    kt, kt_new, key_val;
   1327     soc_mem_t mem_type_new, mem_type;
   1328     soc_field_t field;
   1329     
   1330     /* Since we read everything using a type 1 view only thus, if valid and 
   1331        present then convert the single type 2 entry split across 2 raw type 1
   1332        entries back into a single type 2 entry */
   1333     new_p = new_bucket;
   1334     for (in = 0; in < SOC_TR3_L2X_BUCKET_SIZE; in+=2, 
   1335          new_p += tr3_l2x_data[unit].entry_words_int * 2) {
   1336         if (!L2X_IS_VALID_ENTRY(unit, L2_ENTRY_2m, 
   1337                                 new_p, VALID_0f)) {
   1338             continue;
   1339         }
   1340         kt_new = soc_mem_field32_get(unit, L2_ENTRY_1m, new_p, KEY_TYPEf);
   1341         if ((kt_new == SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE) || 
   1342             (kt_new == SOC_MEM_KEY_L2_ENTRY_2_L2_VFI) ||
   1343             (kt_new == SOC_MEM_KEY_L2_ENTRY_2_L2_TRILL_NONUC_ACCESS)) {
   1344             uint32 tmp[SOC_MAX_MEM_WORDS];
   1345             uint32 *src[4] = {0};
   1346             src[0] = new_p;
   1347             src[1] = new_p + tr3_l2x_data[unit].entry_words_int;
   1348             soc_mem_base_to_wide_entry_conv(unit, L2_ENTRY_2m, L2_ENTRY_1m, 
   1349                                             tmp, src, TYPE_1_TO_TYPE_2);
   1350             sal_memcpy(new_p, tmp, soc_mem_entry_bytes(unit, L2_ENTRY_2m));
   1351         }
   1352     }
   1353     
   1354     /*
   1355      * Process deletions (which will be any entry that was in the bucket
   1356      * before but whose key is no longer found anywhere in the bucket)
   1357      * and changes (which will be any entry whose key is still found but
   1358      * whose associated data (port, etc.) has changed).
   1359      */
   1360 
   1361     old_p = old_bucket;
   1362     new_ptr = new_bucket;
   1363     for (io = 0; io < SOC_TR3_L2X_BUCKET_SIZE; ) {
   1364         /*
   1365          * No deletion or change is needed for invalid entries.
   1366          */
   1367         if (!soc_mem_field32_get(unit, L2_ENTRY_1m, old_p, VALIDf)) {
   1368             io++;
   1369             old_p += tr3_l2x_data[unit].entry_words_int;
   1370             new_ptr += tr3_l2x_data[unit].entry_words_int;
   1371             continue;
   1372         }
   1373         
   1374         /* Determine entry type/size */
   1375         mem_type = L2_ENTRY_1m;
   1376         kt = soc_mem_field32_get(unit, L2_ENTRY_1m, old_p, KEY_TYPEf);
   1377         if ((kt == SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE) || 
   1378             (kt == SOC_MEM_KEY_L2_ENTRY_2_L2_VFI) ||
   1379             (kt == SOC_MEM_KEY_L2_ENTRY_2_L2_TRILL_NONUC_ACCESS)) {
   1380             mem_type = L2_ENTRY_2m;
   1381         }
   1382         
   1383         /*
   1384          * Check if the entry has been deleted and is marked for
   1385          * delete.
   1386          */
   1387         delete_marked = SHR_BITGET(p_chunk_del_map, bucket_index + io);
   1388         callback_suppress = SHR_BITGET(p_chunk_cb_map, bucket_index + io);
   1389 
   1390         /*
   1391          * Quick check: if the entry is identical, it does not need any
   1392          * deletion or change processing.  It may be valid or not.
   1393          */
   1394         if (L2X_ENTRY_EQL(unit, old_p, new_ptr, 0)) {
   1395             /* Entry got learnt again after delete */
   1396             if (delete_marked) {
   1397                 if (callback_suppress) {
   1398                     /* Indicate re-learn */
   1399                     soc_l2_entry_callback(unit, 0, mem_type, NULL,
   1400                                          (l2_combo_entry_t *) new_ptr);
   1401                 } else {
   1402                     /* Indicate delete and re-learn */
   1403                     soc_l2_entry_callback(unit, 0, mem_type, 
   1404                                           (l2_combo_entry_t *) old_p, NULL);
   1405                     soc_l2_entry_callback(unit, 0, mem_type, NULL,
   1406                                           (l2_combo_entry_t *) new_ptr);
   1407                 }
   1408             }
   1409             goto adv_del_process;
   1410         }
   1411 
   1412         /*
   1413          * See if the old key still exists anywhere within the bucket.
   1414          */
   1415         new_p = new_bucket;
   1416         for (in = 0; in < SOC_TR3_L2X_BUCKET_SIZE; ) {
   1417             mem_type_new = L2_ENTRY_1m;
   1418             field = VALIDf;
   1419             kt_new = soc_mem_field32_get(unit, L2_ENTRY_1m, new_p, KEY_TYPEf);
   1420             if ((kt_new == SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE) || 
   1421                 (kt_new == SOC_MEM_KEY_L2_ENTRY_2_L2_VFI) ||
   1422                 (kt_new == SOC_MEM_KEY_L2_ENTRY_2_L2_TRILL_NONUC_ACCESS)) {
   1423                 assert(in % 2 == 0); /* wide entry should never be on odd boundary */
   1424                 mem_type_new = L2_ENTRY_2m;
   1425                 field = VALID_0f;
   1426             }
   1427             if (soc_mem_field32_get(unit, mem_type_new,
   1428                                     new_p, field) &&
   1429                 (soc_mem_compare_key(unit, mem_type_new,
   1430                                      old_p, new_p) == 0)) {
   1431                 break;
   1432             }
   1433             if (mem_type == L2_ENTRY_1m) {
   1434                 if (mem_type_new == L2_ENTRY_1m) {
   1435                     in++;
   1436                     new_p += tr3_l2x_data[unit].entry_words_int;
   1437                 } else {
   1438                     in += 2;
   1439                     new_p += tr3_l2x_data[unit].entry_words_int * 2;
   1440                 }
   1441             } else {
   1442                 in += 2;
   1443                 new_p += tr3_l2x_data[unit].entry_words_int * 2;
   1444             }
   1445         }
   1446 
   1447         if (in == SOC_TR3_L2X_BUCKET_SIZE) {
   1448             /* It doesn't, so issue a delete. */
   1449             if (!callback_suppress) {
   1450                 soc_l2_entry_callback(unit, 0, mem_type, (l2_combo_entry_t *)old_p, 
   1451                                       NULL);
   1452             }
   1453             goto adv_del_process;
   1454         }
   1455 
   1456         /*
   1457          * Check if everything at the new location is the same (ignoring
   1458          * hit bit).  If so, there is no delete or change processing.
   1459          */
   1460         if (!(shadow_hit_bits & L2X_SHADOW_HIT_BITS)) {
   1461             if (!(shadow_hit_bits & L2X_SHADOW_HIT_DST)) { 
   1462                 soc_mem_field32_set(unit, mem_type, old_p, HITDAf,
   1463                                     soc_mem_field32_get(unit, mem_type,
   1464                                                         new_p, HITDAf));
   1465             }
   1466             if (!(shadow_hit_bits & L2X_SHADOW_HIT_SRC)) {
   1467                 soc_mem_field32_set(unit, mem_type, old_p, HITSAf,
   1468                                     soc_mem_field32_get(unit, mem_type,
   1469                                                         new_p, HITSAf));
   1470             }
   1471         }
   1472 
   1473         if (L2X_ENTRY_EQL(unit, old_p, new_p, shadow_hit_bits)) {
   1474             /* Entry got learnt again after delete */
   1475             if (delete_marked) {
   1476                 if (callback_suppress) {
   1477                     /* Indicate re-learn */
   1478                     soc_l2_entry_callback(unit, 0, mem_type, NULL, 
   1479                                          (l2_combo_entry_t *) new_ptr);
   1480                 } else {
   1481                     /* Indicate delete and re-learn */
   1482                     soc_l2_entry_callback(unit, 0, mem_type, 
   1483                                           (l2_combo_entry_t *) old_p, NULL);
   1484                     soc_l2_entry_callback(unit, 0, mem_type, NULL,
   1485                                           (l2_combo_entry_t *) new_ptr);
   1486                 }
   1487             }
   1488             goto adv_del_process;
   1489         }
   1490 
   1491         /* Issue change (delete & insert) */
   1492         if (!callback_suppress) {
   1493             soc_l2_entry_callback(unit, 0, mem_type,
   1494                                   (l2_combo_entry_t *) old_p,
   1495                                   (l2_combo_entry_t *) new_p);
   1496         }
   1497 
   1498 adv_del_process:        
   1499         if (mem_type == L2_ENTRY_1m) {
   1500             io++;
   1501             old_p += tr3_l2x_data[unit].entry_words_int;
   1502             new_ptr += tr3_l2x_data[unit].entry_words_int;
   1503         } else {
   1504             io += 2;
   1505             old_p += tr3_l2x_data[unit].entry_words_int * 2;
   1506             new_ptr += tr3_l2x_data[unit].entry_words_int * 2;
   1507         }        
   1508     }
   1509 
   1510     /*
   1511      * Process insertions, which will be any entry whose key was not in
   1512      * the bucket before, but is now.
   1513      */
   1514 
   1515     new_p = new_bucket;
   1516     old_ptr = old_bucket;
   1517     for (in = 0; in < SOC_TR3_L2X_BUCKET_SIZE; ) {
   1518         /* Determine entry type/size */
   1519         mem_type = L2_ENTRY_1m;
   1520         kt = soc_mem_field32_get(unit, L2_ENTRY_1m, new_p, KEY_TYPEf);
   1521         if ((kt == SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE) || 
   1522             (kt == SOC_MEM_KEY_L2_ENTRY_2_L2_VFI) ||
   1523             (kt == SOC_MEM_KEY_L2_ENTRY_2_L2_TRILL_NONUC_ACCESS)) {
   1524             mem_type = L2_ENTRY_2m;
   1525         }
   1526         
   1527         /*
   1528          * Quick check: if the entry is identical, it does not need any
   1529          * insertion processing.  It may be valid or not.
   1530          */
   1531         if (L2X_ENTRY_EQL(unit, new_p, old_ptr, 0)) {
   1532             goto adv_ins_process;
   1533         }
   1534 
   1535         /*
   1536          * No insert needed for invalid entries.
   1537          */
   1538         if (!soc_mem_field32_get(unit, L2_ENTRY_1m, new_p, VALIDf)) {
   1539             in++;
   1540             new_p += tr3_l2x_data[unit].entry_words_int;
   1541             old_ptr += tr3_l2x_data[unit].entry_words_int;
   1542             continue;
   1543         }
   1544 
   1545         /*
   1546          * If the same key already existed elsewhere within the bucket,
   1547          * it has already been taken care of by the change processing.
   1548          */
   1549 
   1550         old_p = old_bucket;
   1551         for (io = 0; io < SOC_TR3_L2X_BUCKET_SIZE; ) {
   1552             mem_type_new = L2_ENTRY_1m;
   1553             field = VALIDf;
   1554             kt_new = soc_mem_field32_get(unit, L2_ENTRY_1m, old_p, KEY_TYPEf);
   1555             if ((kt_new == SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE) || 
   1556                 (kt_new == SOC_MEM_KEY_L2_ENTRY_2_L2_VFI) ||
   1557                 (kt_new == SOC_MEM_KEY_L2_ENTRY_2_L2_TRILL_NONUC_ACCESS)) {
   1558                 assert(io % 2 == 0); /* wide entry should never be on odd boundary */
   1559                 mem_type_new = L2_ENTRY_2m;
   1560                 field = VALID_0f;
   1561             }
   1562             if (soc_mem_field32_get(unit, mem_type_new,
   1563                                     old_p, field) &&
   1564                 soc_mem_compare_key(unit, mem_type_new,
   1565                                     new_p, old_p) == 0) {
   1566                 break;
   1567             }
   1568             if (mem_type == L2_ENTRY_1m) {
   1569                 if (mem_type_new == L2_ENTRY_1m) {
   1570                     io++;
   1571                     old_p += tr3_l2x_data[unit].entry_words_int;
   1572                 } else {
   1573                     io += 2;
   1574                     old_p += tr3_l2x_data[unit].entry_words_int * 2;
   1575                 }
   1576             } else {
   1577                 io += 2;
   1578                 old_p += tr3_l2x_data[unit].entry_words_int * 2;
   1579             }
   1580         }
   1581 
   1582         if (io < SOC_TR3_L2X_BUCKET_SIZE) {
   1583             goto adv_ins_process;
   1584         }
   1585 
   1586         if (soc_feature(unit, soc_feature_ppa_bypass)) {
   1587             if (SOC_CONTROL(unit)->l2x_ppa_bypass == FALSE) {
   1588                 if (mem_type == L2_ENTRY_1m) {
   1589                     key_val = SOC_MEM_KEY_L2_ENTRY_1_L2_BRIDGE;
   1590                 } else {
   1591                     key_val = SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE;
   1592                 } 
   1593                 if (soc_mem_field32_get(unit, mem_type, new_p, KEY_TYPEf) !=
   1594                     key_val) {
   1595                     SOC_CONTROL(unit)->l2x_ppa_bypass = TRUE;
   1596                 }
   1597             }
   1598         }
   1599 
   1600         /* Issue insert */
   1601         delete_marked = SHR_BITGET(p_chunk_del_map, bucket_index + in);
   1602         if (!delete_marked) {
   1603             soc_l2_entry_callback(unit, 0, mem_type, NULL, 
   1604                                   (l2_combo_entry_t *)new_p);
   1605         } else {
   1606             /* Special case - New entry but marked for deletion by now */
   1607             soc_l2_entry_callback(unit, 0, mem_type, (l2_combo_entry_t *)new_p,
   1608                                   (l2_combo_entry_t *)new_p);
   1609         }
   1610 
   1611 adv_ins_process:        
   1612         if (mem_type == L2_ENTRY_1m) {        
   1613             in++;
   1614             new_p += tr3_l2x_data[unit].entry_words_int;
   1615             old_ptr += tr3_l2x_data[unit].entry_words_int;
   1616         } else {
   1617             in += 2;
   1618             new_p += tr3_l2x_data[unit].entry_words_int * 2;
   1619             old_ptr += tr3_l2x_data[unit].entry_words_int *2;
   1620         }
   1621     }
   1622 
   1623     /* Sync shadow copy */
   1624 
   1625     sal_memcpy(old_bucket, new_bucket,
   1626                SOC_TR3_L2X_BUCKET_SIZE * tr3_l2x_data[unit].entry_words_int*4);
   1627 }
   1628 
   1629 /*
   1630  * Function:
   1631  * 	_soc_tr3_l2x_thread
   1632  * Purpose:
   1633  *   	Thread control for L2 shadow table maintenance
   1634  * Parameters:
   1635  *	unit_vp - StrataSwitch unit # (as a void *).
   1636  * Returns:
   1637  *	Nothing
   1638  * Notes:
   1639  *	Exits when l2x_rate is set to zero and semaphore is given.  The
   1640  *	table is processed one chunk at a time (spn_L2XMSG_CHUNKS chunks
   1641  *	total) in order to reduce memory requirements for the temporary
   1642  *	DMA buffer and to give the CPU a break from bursts of activity.
   1643  */
   1644 
   1645 STATIC void
   1646 _soc_tr3_l2x_thread(void *unit_vp)
   1647 {
   1648     int           unit = PTR_TO_INT(unit_vp);
   1649     soc_control_t *soc = SOC_CONTROL(unit);
   1650     int           rv;
   1651     uint32        *shadow_tab = NULL;
   1652     uint32        *chunk_buf_int = NULL;
   1653     uint32        *chunk_buf_ext1 = NULL, *chunk_buf_ext2 = NULL;
   1654     SHR_BITDCL    *del_map_int = NULL;
   1655     SHR_BITDCL    *del_map_ext1 = NULL, *del_map_ext2 = NULL;
   1656     SHR_BITDCL    *chunk_del_map_int = NULL;
   1657     SHR_BITDCL    *chunk_del_map_ext1 = NULL, *chunk_del_map_ext2 = NULL;
   1658     SHR_BITDCL    *cb_map_int = NULL, *cb_map_ext1 = NULL, *cb_map_ext2 = NULL;
   1659     SHR_BITDCL    *chunk_cb_map_int = NULL;
   1660     SHR_BITDCL    *chunk_cb_map_ext1 = NULL, *chunk_cb_map_ext2 = NULL;
   1661     int           index_count_int, index_count_ext1 = 0, index_count_ext2 = 0;
   1662     int           chunk_count_int = 0, chunk_size_int = 0;
   1663     int           chunk_count_ext1 = 0, chunk_size_ext1 = 0;
   1664     int           chunk_count_ext2 = 0, chunk_size_ext2 = 0;
   1665     int           chunk_index_int = 0, bucket_index, index;
   1666     int           chunk_index_ext1 = 0, chunk_index_ext2 = 0;
   1667     uint32        *tab_p_int = NULL, *buf_p;
   1668     uint32        *tab_p_ext1 = NULL, *tab_p_ext2 = NULL;
   1669     int           interval, delete_marked, callback_suppress;
   1670     sal_usecs_t   stime, etime;
   1671     int           iter = 0;
   1672 
   1673     tr3_l2x_data[unit].shadow_tab_int = NULL;
   1674     tr3_l2x_data[unit].shadow_tab_ext1 = NULL;
   1675     tr3_l2x_data[unit].shadow_tab_ext2 = NULL;
   1676     
   1677     tr3_l2x_data[unit].entry_bytes_int = soc_mem_entry_bytes(unit, L2_ENTRY_1m);
   1678     tr3_l2x_data[unit].entry_words_int = soc_mem_entry_words(unit, L2_ENTRY_1m);
   1679 
   1680     index_count_int = soc_mem_index_count(unit, L2_ENTRY_1m);
   1681     if (index_count_int <= 0) {
   1682         LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1683                     (BSL_META_U(unit,
   1684                                 "soc_tr3_l2x_thread: Internal L2 table size is 0 \n")));
   1685         tr3_l2x_data[unit].int_avail = FALSE;
   1686         goto skip_l2_int;
   1687     } else {
   1688         tr3_l2x_data[unit].int_avail = TRUE;
   1689     }
   1690     
   1691     chunk_count_int = soc_property_get(unit, spn_L2XMSG_CHUNKS, 4);
   1692     chunk_size_int = index_count_int / chunk_count_int;
   1693 
   1694     assert(chunk_size_int > 0);
   1695     assert(chunk_size_int % SOC_TR3_L2X_BUCKET_SIZE == 0);
   1696 
   1697     shadow_tab = sal_alloc(index_count_int * tr3_l2x_data[unit].entry_words_int * 4,
   1698                            "l2x_old");
   1699 
   1700     chunk_buf_int = soc_cm_salloc(unit,
   1701                               chunk_size_int * tr3_l2x_data[unit].entry_words_int * 4,
   1702                               "l2x_new");
   1703 
   1704     del_map_int = sal_alloc(SHR_BITALLOCSIZE(index_count_int), "l2x_delete_map");
   1705     cb_map_int = sal_alloc(SHR_BITALLOCSIZE(index_count_int), "l2x_callback_map");
   1706 
   1707     chunk_del_map_int = 
   1708     sal_alloc(SHR_BITALLOCSIZE(chunk_size_int), "l2x_chunk_delete_map");
   1709     chunk_cb_map_int = 
   1710     sal_alloc(SHR_BITALLOCSIZE(chunk_size_int), "l2x_chunk_callback_map");
   1711 
   1712     if (shadow_tab == NULL || chunk_buf_int == NULL || 
   1713         del_map_int == NULL || chunk_del_map_int == NULL || 
   1714         cb_map_int == NULL || chunk_cb_map_int == NULL) {
   1715         LOG_ERROR(BSL_LS_SOC_L2,
   1716                   (BSL_META_U(unit,
   1717                               "AbnormalThreadExit:soc_l2x_thread: not enough memory \n")));
   1718         soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
   1719                            SOC_SWITCH_EVENT_THREAD_L2X, __LINE__, SOC_E_MEMORY);
   1720         goto cleanup_exit;
   1721     }
   1722     /*
   1723      * Start with initially empty shadow table.
   1724      */
   1725 
   1726     sal_memset(shadow_tab, 0, index_count_int * tr3_l2x_data[unit].entry_words_int * 4);
   1727 
   1728     /*
   1729      * Clear the delete and callback map.
   1730      */
   1731     SHR_BITCLR_RANGE(del_map_int, 0, index_count_int);
   1732     SHR_BITCLR_RANGE(cb_map_int, 0, index_count_int);
   1733 
   1734     tr3_l2x_data[unit].shadow_tab_int = shadow_tab;
   1735     tr3_l2x_data[unit].del_map_int = del_map_int;
   1736     tr3_l2x_data[unit].cb_map_int = cb_map_int;
   1737 
   1738     tab_p_int = shadow_tab;
   1739 
   1740     shadow_tab = NULL;
   1741 
   1742 skip_l2_int:
   1743     if (!soc_feature(unit, soc_feature_esm_support)) {
   1744         goto skip_l2_ext2;
   1745     }
   1746     
   1747     tr3_l2x_data[unit].entry_bytes_ext1 = soc_mem_entry_bytes(unit, EXT_L2_ENTRY_1m);
   1748     tr3_l2x_data[unit].entry_words_ext1 = soc_mem_entry_words(unit, EXT_L2_ENTRY_1m);
   1749 
   1750     index_count_ext1 = soc_mem_index_count(unit, EXT_L2_ENTRY_1m);
   1751     if (index_count_ext1 <= 0) {
   1752         LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1753                     (BSL_META_U(unit,
   1754                                 "soc_tr3_l2x_thread: External L2_1 table size is 0 \n")));
   1755         tr3_l2x_data[unit].ext1_avail = FALSE;
   1756         goto skip_l2_ext1;
   1757     } else {
   1758         tr3_l2x_data[unit].ext1_avail = TRUE;
   1759     }
   1760     
   1761     chunk_count_ext1 = soc_property_get(unit, spn_L2XMSG_CHUNKS, 4);
   1762     chunk_size_ext1 = index_count_ext1 / chunk_count_ext1;
   1763 
   1764     assert(chunk_size_ext1 > 0);
   1765     assert(chunk_size_ext1 % SOC_TR3_L2X_BUCKET_SIZE == 0);
   1766 
   1767     shadow_tab = sal_alloc(index_count_ext1 * tr3_l2x_data[unit].entry_words_ext1 * 4,
   1768                            "l2x_old");
   1769 
   1770     chunk_buf_ext1 = soc_cm_salloc(unit, chunk_size_ext1 * 
   1771                                    tr3_l2x_data[unit].entry_words_ext1 * 4,
   1772                                    "l2x_new");
   1773 
   1774     del_map_ext1 = sal_alloc(SHR_BITALLOCSIZE(index_count_ext1), "l2x_delete_map");
   1775     cb_map_ext1 = sal_alloc(SHR_BITALLOCSIZE(index_count_ext1), "l2x_callback_map");
   1776 
   1777     chunk_del_map_ext1 = 
   1778     sal_alloc(SHR_BITALLOCSIZE(chunk_size_ext1), "l2x_chunk_delete_map");
   1779     chunk_cb_map_ext1 = 
   1780     sal_alloc(SHR_BITALLOCSIZE(chunk_size_ext1), "l2x_chunk_callback_map");
   1781 
   1782     if (shadow_tab == NULL || chunk_buf_ext1 == NULL || 
   1783         del_map_ext1 == NULL || chunk_del_map_ext1 == NULL || 
   1784         cb_map_ext1 == NULL || chunk_cb_map_ext1 == NULL) {
   1785         LOG_ERROR(BSL_LS_SOC_L2,
   1786                   (BSL_META_U(unit,
   1787                               "AbnormalThreadExit:soc_l2x_thread: not enough memory \n")));
   1788         soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
   1789                            SOC_SWITCH_EVENT_THREAD_L2X, __LINE__, SOC_E_MEMORY);
   1790         goto cleanup_exit;
   1791     }
   1792     /*
   1793      * Start with initially empty shadow table.
   1794      */
   1795     sal_memset(shadow_tab, 0, index_count_ext1 * tr3_l2x_data[unit].entry_words_ext1 * 4);
   1796     buf_p = shadow_tab;
   1797     for (index = 0; index < index_count_ext1; index ++) {
   1798         soc_mem_field32_set(unit, EXT_L2_ENTRY_1m, buf_p, FREEf, 1);
   1799         buf_p += tr3_l2x_data[unit].entry_words_ext1;
   1800     }
   1801 
   1802     /*
   1803      * Clear the delete and callback map.
   1804      */
   1805     SHR_BITCLR_RANGE(del_map_ext1, 0, index_count_ext1);
   1806     SHR_BITCLR_RANGE(cb_map_ext1, 0, index_count_ext1);
   1807 
   1808     tr3_l2x_data[unit].shadow_tab_ext1 = shadow_tab;
   1809     tr3_l2x_data[unit].del_map_ext1 = del_map_ext1;
   1810     tr3_l2x_data[unit].cb_map_ext1 = cb_map_ext1;
   1811 
   1812     tab_p_ext1 = shadow_tab;    
   1813 
   1814     shadow_tab = NULL;
   1815 
   1816 skip_l2_ext1:
   1817     tr3_l2x_data[unit].entry_bytes_ext2 = soc_mem_entry_bytes(unit, EXT_L2_ENTRY_2m);
   1818     tr3_l2x_data[unit].entry_words_ext2 = soc_mem_entry_words(unit, EXT_L2_ENTRY_2m);
   1819 
   1820     index_count_ext2 = soc_mem_index_count(unit, EXT_L2_ENTRY_2m);
   1821     if (index_count_ext2 <= 0) {
   1822         LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1823                     (BSL_META_U(unit,
   1824                                 "soc_tr3_l2x_thread: External L2_2 table size is 0 \n")));
   1825         tr3_l2x_data[unit].ext2_avail = FALSE;
   1826         goto skip_l2_ext2;
   1827     } else {
   1828         tr3_l2x_data[unit].ext2_avail = TRUE;
   1829     }
   1830     
   1831     chunk_count_ext2 = soc_property_get(unit, spn_L2XMSG_CHUNKS, 4);
   1832     chunk_size_ext2 = index_count_ext2 / chunk_count_ext2;
   1833 
   1834     assert(chunk_size_ext2 > 0);
   1835     assert(chunk_size_ext2 % SOC_TR3_L2X_BUCKET_SIZE == 0);
   1836 
   1837     shadow_tab = sal_alloc(index_count_ext2 * tr3_l2x_data[unit].entry_words_ext2 * 4,
   1838                            "l2x_old");
   1839 
   1840     chunk_buf_ext2 = soc_cm_salloc(unit, chunk_size_ext2 * 
   1841                                    tr3_l2x_data[unit].entry_words_ext2 * 4,
   1842                                    "l2x_new");
   1843 
   1844     del_map_ext2 = sal_alloc(SHR_BITALLOCSIZE(index_count_ext2), "l2x_delete_map");
   1845     cb_map_ext2 = sal_alloc(SHR_BITALLOCSIZE(index_count_ext2), "l2x_callback_map");
   1846 
   1847     chunk_del_map_ext2 = 
   1848     sal_alloc(SHR_BITALLOCSIZE(chunk_size_ext2), "l2x_chunk_delete_map");
   1849     chunk_cb_map_ext2 = 
   1850     sal_alloc(SHR_BITALLOCSIZE(chunk_size_ext2), "l2x_chunk_callback_map");
   1851 
   1852     if (shadow_tab == NULL || chunk_buf_ext2 == NULL || 
   1853         del_map_ext2 == NULL || chunk_del_map_ext2 == NULL || 
   1854         cb_map_ext2 == NULL || chunk_cb_map_ext2 == NULL) {
   1855         LOG_ERROR(BSL_LS_SOC_L2,
   1856                   (BSL_META_U(unit,
   1857                               "AbnormalThreadExit:soc_l2x_thread: not enough memory \n")));
   1858         soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
   1859                            SOC_SWITCH_EVENT_THREAD_L2X, __LINE__, SOC_E_MEMORY);
   1860         goto cleanup_exit;
   1861     }
   1862     /*
   1863      * Start with initially empty shadow table.
   1864      */
   1865     sal_memset(shadow_tab, 0, index_count_ext2 * tr3_l2x_data[unit].entry_words_ext2 * 4);
   1866     buf_p = shadow_tab;
   1867     for (index = 0; index < index_count_ext2; index ++) {
   1868         soc_mem_field32_set(unit, EXT_L2_ENTRY_2m, buf_p, FREEf, 1);
   1869         buf_p += tr3_l2x_data[unit].entry_words_ext2;
   1870     }
   1871 
   1872     /*
   1873      * Clear the delete and callback map.
   1874      */
   1875     SHR_BITCLR_RANGE(del_map_ext2, 0, index_count_ext2);
   1876     SHR_BITCLR_RANGE(cb_map_ext2, 0, index_count_ext2);
   1877 
   1878     tr3_l2x_data[unit].shadow_tab_ext2 = shadow_tab;
   1879     tr3_l2x_data[unit].del_map_ext2 = del_map_ext2;
   1880     tr3_l2x_data[unit].cb_map_ext2 = cb_map_ext2;
   1881 
   1882     tab_p_ext2 = shadow_tab;    
   1883     
   1884     shadow_tab = NULL;
   1885 
   1886 skip_l2_ext2:
   1887     if (tr3_l2x_data[unit].int_avail == FALSE && 
   1888         tr3_l2x_data[unit].ext1_avail == FALSE && 
   1889         tr3_l2x_data[unit].ext2_avail == FALSE) {
   1890         soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
   1891                            SOC_SWITCH_EVENT_THREAD_L2X, __LINE__, SOC_E_EMPTY);
   1892         goto no_cleanup_exit;
   1893     }
   1894     /*
   1895      * For 'POLL' mode, set the 'enabled' to '1',
   1896      * to indicate L2 data store.
   1897      */
   1898     tr3_l2x_data[unit].enabled = 1;
   1899 
   1900     while ((interval = soc->l2x_interval) != 0) {
   1901         /*
   1902          * Read the next chunk of the L2 table using Table DMA.
   1903          */
   1904         stime = sal_time_usecs();
   1905 
   1906         /*
   1907          * If running for the first time wait for
   1908          * duration = interval
   1909          */
   1910         if (!iter) {
   1911             goto continue_loop;
   1912         }
   1913 
   1914         if (tr3_l2x_data[unit].int_avail == FALSE) {
   1915             goto skip_l2_int_loop;
   1916         }
   1917         LOG_VERBOSE(BSL_LS_SOC_ARL,
   1918                     (BSL_META_U(unit,
   1919                                 "soc_l2x_thread: Process INT %d-%d\n"),
   1920                      chunk_index_int, chunk_index_int + chunk_size_int - 1));
   1921         SOC_MEM_L2_INT_LOCK(unit);
   1922         if (SOC_L2_DEL_SYNC_LOCK(soc) < 0) {
   1923             LOG_ERROR(BSL_LS_SOC_L2,
   1924                       (BSL_META_U(unit,
   1925                                   "AbnormalThreadExit:soc_l2x_thread: unable to take mutex\n")));
   1926             SOC_MEM_L2_INT_UNLOCK(unit);
   1927             soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
   1928                                SOC_SWITCH_EVENT_THREAD_L2X, __LINE__,
   1929                                SOC_E_RESOURCE);
   1930             goto cleanup_exit;
   1931         }
   1932 
   1933         if ((rv = soc_mem_read_range(unit, L2_ENTRY_1m,
   1934                                      MEM_BLOCK_ANY, chunk_index_int,
   1935                                      chunk_index_int + chunk_size_int - 1,
   1936                                      chunk_buf_int)) < 0) {
   1937             SOC_L2_DEL_SYNC_UNLOCK(soc);
   1938             SOC_MEM_L2_INT_UNLOCK(unit);
   1939             LOG_ERROR(BSL_LS_SOC_L2,
   1940                       (BSL_META_U(unit,
   1941                                   "AbnormalThreadExit:soc_l2x_thread: DMA failed: %s\n"),
   1942                                   soc_errmsg(rv)));
   1943 
   1944             soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
   1945                                SOC_SWITCH_EVENT_THREAD_L2X, __LINE__, rv);
   1946 
   1947             goto cleanup_exit;
   1948         } else {
   1949             SHR_BITCOPY_RANGE(chunk_del_map_int, 0, del_map_int, chunk_index_int, 
   1950                               chunk_size_int);
   1951             SHR_BITCOPY_RANGE(chunk_cb_map_int, 0, cb_map_int, chunk_index_int, 
   1952                               chunk_size_int);
   1953 
   1954             SHR_BITCLR_RANGE(del_map_int, chunk_index_int, chunk_size_int);
   1955             SHR_BITCLR_RANGE(cb_map_int, chunk_index_int, chunk_size_int);
   1956 
   1957             SOC_L2_DEL_SYNC_UNLOCK(soc);
   1958             SOC_MEM_L2_INT_UNLOCK(unit);
   1959 
   1960             /*
   1961              * Scan, compare, and sync the old and new chunks one bucket
   1962              * at a time.
   1963              */
   1964             buf_p = chunk_buf_int;
   1965             for (bucket_index = 0; bucket_index < chunk_size_int; 
   1966                 bucket_index += SOC_TR3_L2X_BUCKET_SIZE) {
   1967                 _soc_tr3_l2x_sync_bucket(unit, tab_p_int, buf_p, 
   1968                                          soc->l2x_shadow_hit_bits,
   1969                                          bucket_index, chunk_del_map_int, 
   1970                                          chunk_cb_map_int);
   1971                 tab_p_int += tr3_l2x_data[unit].entry_words_int * SOC_TR3_L2X_BUCKET_SIZE;
   1972                 buf_p += tr3_l2x_data[unit].entry_words_int * SOC_TR3_L2X_BUCKET_SIZE;
   1973             }
   1974 
   1975             if ((chunk_index_int += chunk_size_int) >= index_count_int) {
   1976                 chunk_index_int = 0;
   1977                 tab_p_int = tr3_l2x_data[unit].shadow_tab_int;
   1978             }
   1979         }
   1980 
   1981 skip_l2_int_loop:
   1982         if (!soc_feature(unit, soc_feature_esm_support)) {
   1983             goto continue_loop;
   1984         }        
   1985         if (tr3_l2x_data[unit].ext1_avail == FALSE) {
   1986             goto skip_l2_ext1_loop;
   1987         }
   1988         LOG_VERBOSE(BSL_LS_SOC_ARL,
   1989                     (BSL_META_U(unit,
   1990                                 "soc_l2x_thread: Process EXT1 %d-%d\n"),
   1991                      chunk_index_ext1, chunk_index_ext1 + chunk_size_ext1 - 1));
   1992 
   1993         /* First work on EXT_L2_ENTRY_1 */
   1994         SOC_MEM_L2_EXT_1_LOCK(unit);
   1995         if (SOC_L2_DEL_SYNC_LOCK(soc) < 0) {
   1996             LOG_ERROR(BSL_LS_SOC_L2,
   1997                       (BSL_META_U(unit,
   1998                                   "AbnormalThreadExit:soc_l2x_thread: unable to take mutex\n")));
   1999             SOC_MEM_L2_INT_UNLOCK(unit);
   2000             soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
   2001                                SOC_SWITCH_EVENT_THREAD_L2X, __LINE__,
   2002                                SOC_E_RESOURCE);
   2003             goto cleanup_exit;
   2004         }
   2005 
   2006         if ((rv = soc_mem_read_range(unit, EXT_L2_ENTRY_1m,
   2007                                      MEM_BLOCK_ANY, chunk_index_ext1,
   2008                                      chunk_index_ext1 + chunk_size_ext1 - 1,
   2009                                      chunk_buf_ext1)) < 0) {
   2010             SOC_L2_DEL_SYNC_UNLOCK(soc);
   2011             SOC_MEM_L2_EXT_1_UNLOCK(unit);
   2012             LOG_ERROR(BSL_LS_SOC_L2,
   2013                       (BSL_META_U(unit,
   2014                                   "AbnormalThreadExit:soc_l2x_thread: DMA failed: %s\n"),
   2015                                   soc_errmsg(rv)));
   2016 
   2017             soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
   2018                                SOC_SWITCH_EVENT_THREAD_L2X, __LINE__, rv);
   2019 
   2020             goto cleanup_exit;
   2021         } else {
   2022             SHR_BITCOPY_RANGE(chunk_del_map_ext1, 0, del_map_ext1, chunk_index_ext1, 
   2023                               chunk_size_ext1);
   2024             SHR_BITCOPY_RANGE(chunk_cb_map_ext1, 0, cb_map_ext1, chunk_index_ext1, 
   2025                               chunk_size_ext1);
   2026 
   2027             SHR_BITCLR_RANGE(del_map_ext1, chunk_index_ext1, chunk_size_ext1);
   2028             SHR_BITCLR_RANGE(cb_map_ext1, chunk_index_ext1, chunk_size_ext1);
   2029 
   2030             SOC_L2_DEL_SYNC_UNLOCK(soc);
   2031             SOC_MEM_L2_EXT_1_UNLOCK(unit);
   2032 
   2033             /*
   2034              * Scan, compare, and sync the old and new chunks.
   2035              */
   2036             buf_p = chunk_buf_ext1;
   2037             for (index = 0; index < chunk_size_ext1; index ++) {
   2038                 /* Check if old entry was free */
   2039                 if (soc_mem_field32_get(unit, EXT_L2_ENTRY_1m, tab_p_ext1, FREEf)) {
   2040                     /* if new entry is used then issue insert cb */
   2041                     if (!soc_mem_field32_get(unit, EXT_L2_ENTRY_1m, buf_p, FREEf)) {
   2042                         delete_marked = SHR_BITGET(chunk_del_map_ext1, index);
   2043                         if (!delete_marked) {
   2044                             soc_l2_entry_callback(unit, 0, EXT_L2_ENTRY_1m, NULL, 
   2045                                                   (l2_combo_entry_t *)buf_p);
   2046                         } else {
   2047                             /* Special case - New entry but marked for deletion by now */
   2048                             soc_l2_entry_callback(unit, 0, EXT_L2_ENTRY_1m, 
   2049                                                   (l2_combo_entry_t *)buf_p, 
   2050                                                   (l2_combo_entry_t *)buf_p);
   2051                         }
   2052                     }
   2053                 } else {
   2054                     /* If the new entry is free then issue del cb */
   2055                     if (soc_mem_field32_get(unit, EXT_L2_ENTRY_1m, buf_p, FREEf)) {
   2056                         callback_suppress = SHR_BITGET(chunk_cb_map_ext1, index);
   2057                         if (!callback_suppress) {
   2058                             soc_l2_entry_callback(unit, 0, EXT_L2_ENTRY_1m, 
   2059                                                   (l2_combo_entry_t *)tab_p_ext1, NULL);
   2060                         }
   2061                     } else {
   2062                         /* If new entry is different then issue a replace (del+ins) cb */
   2063                         delete_marked = SHR_BITGET(chunk_del_map_ext1, index);
   2064                         callback_suppress = SHR_BITGET(chunk_cb_map_ext1, index);
   2065                         if (!(soc->l2x_shadow_hit_bits & L2X_SHADOW_HIT_BITS)) {
   2066                             if (!(soc->l2x_shadow_hit_bits & L2X_SHADOW_HIT_DST)) { 
   2067                                 soc_mem_field32_set(unit, EXT_L2_ENTRY_1m, tab_p_ext1, 
   2068                                     HITDAf, soc_mem_field32_get(unit, 
   2069                                                                 EXT_L2_ENTRY_1m,
   2070                                                                 buf_p, HITDAf));
   2071                             }
   2072                             if (!(soc->l2x_shadow_hit_bits & L2X_SHADOW_HIT_SRC)) {
   2073                                 soc_mem_field32_set(unit, EXT_L2_ENTRY_1m, tab_p_ext1, 
   2074                                     HITSAf, soc_mem_field32_get(unit, 
   2075                                                                 EXT_L2_ENTRY_1m,
   2076                                                                 buf_p, HITSAf));
   2077                             }
   2078                         }
   2079                         if (EXT_L2X_1_ENTRY_EQL(unit, tab_p_ext1, buf_p, 
   2080                                                 soc->l2x_shadow_hit_bits)) {
   2081                             if (delete_marked && !callback_suppress) {
   2082                                 soc_l2_entry_callback(unit, 0, EXT_L2_ENTRY_1m,
   2083                                     (l2_combo_entry_t *)tab_p_ext1, NULL);
   2084                             }
   2085                         } else {
   2086                             if (delete_marked && !callback_suppress) {
   2087                                 soc_l2_entry_callback(unit, 0, EXT_L2_ENTRY_1m,
   2088                                     (l2_combo_entry_t *)tab_p_ext1,
   2089                                     (l2_combo_entry_t *)buf_p);
   2090                             }
   2091                         }
   2092                     }
   2093                 }
   2094                 sal_memcpy(tab_p_ext1, buf_p, tr3_l2x_data[unit].entry_words_ext1 * 4);
   2095                 tab_p_ext1 += tr3_l2x_data[unit].entry_words_ext1;
   2096                 buf_p += tr3_l2x_data[unit].entry_words_ext1;
   2097             }
   2098 
   2099             if ((chunk_index_ext1 += chunk_size_ext1) >= index_count_ext1) {
   2100                 chunk_index_ext1 = 0;
   2101                 tab_p_ext1 = tr3_l2x_data[unit].shadow_tab_ext1;
   2102             }
   2103         }
   2104         
   2105 skip_l2_ext1_loop:
   2106         if (tr3_l2x_data[unit].ext2_avail == FALSE) {
   2107             goto continue_loop;
   2108         }
   2109         LOG_VERBOSE(BSL_LS_SOC_ARL,
   2110                     (BSL_META_U(unit,
   2111                                 "soc_l2x_thread: Process EXT2 %d-%d\n"),
   2112                      chunk_index_ext2, chunk_index_ext2 + chunk_size_ext2 - 1));
   2113         /* Then work on EXT_L2_ENTRY_2 */
   2114         SOC_MEM_L2_EXT_2_LOCK(unit);
   2115         if (SOC_L2_DEL_SYNC_LOCK(soc) < 0) {
   2116             LOG_ERROR(BSL_LS_SOC_L2,
   2117                       (BSL_META_U(unit,
   2118                                   "AbnormalThreadExit:soc_l2x_thread: unable to take mutex\n")));
   2119             SOC_MEM_L2_INT_UNLOCK(unit);
   2120             soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
   2121                                SOC_SWITCH_EVENT_THREAD_L2X, __LINE__,
   2122                                SOC_E_RESOURCE);
   2123             goto cleanup_exit;
   2124         }
   2125 
   2126         if ((rv = soc_mem_read_range(unit, EXT_L2_ENTRY_2m,
   2127                                      MEM_BLOCK_ANY, chunk_index_ext2,
   2128                                      chunk_index_ext2 + chunk_size_ext2 - 1,
   2129                                      chunk_buf_ext2)) < 0) {
   2130             SOC_L2_DEL_SYNC_UNLOCK(soc);
   2131             SOC_MEM_L2_EXT_2_UNLOCK(unit);
   2132             LOG_ERROR(BSL_LS_SOC_L2,
   2133                       (BSL_META_U(unit,
   2134                                   "AbnormalThreadExit:soc_l2x_thread: DMA failed: %s\n"),
   2135                                   soc_errmsg(rv)));
   2136 
   2137             soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
   2138                                SOC_SWITCH_EVENT_THREAD_L2X, __LINE__, rv);
   2139 
   2140             goto cleanup_exit;
   2141         } else {
   2142             SHR_BITCOPY_RANGE(chunk_del_map_ext2, 0, del_map_ext2, chunk_index_ext2, 
   2143                               chunk_size_ext2);
   2144             SHR_BITCOPY_RANGE(chunk_cb_map_ext2, 0, cb_map_ext2, chunk_index_ext2, 
   2145                               chunk_size_ext2);
   2146 
   2147             SHR_BITCLR_RANGE(del_map_ext2, chunk_index_ext2, chunk_size_ext2);
   2148             SHR_BITCLR_RANGE(cb_map_ext2, chunk_index_ext2, chunk_size_ext2);
   2149 
   2150             SOC_L2_DEL_SYNC_UNLOCK(soc);
   2151             SOC_MEM_L2_EXT_2_UNLOCK(unit);
   2152 
   2153             /*
   2154              * Scan, compare, and sync the old and new chunks.
   2155              */
   2156             buf_p = chunk_buf_ext2;
   2157             for (index = 0; index < chunk_size_ext2; index ++) {
   2158                 /* Check if old entry was free */
   2159                 if (soc_mem_field32_get(unit, EXT_L2_ENTRY_2m, tab_p_ext2, FREEf)) {
   2160                     /* if new entry is used then issue insert cb */
   2161                     if (!soc_mem_field32_get(unit, EXT_L2_ENTRY_2m, buf_p, FREEf)) {
   2162                         delete_marked = SHR_BITGET(chunk_del_map_ext2, index);
   2163                         if (!delete_marked) {
   2164                             soc_l2_entry_callback(unit, 0, EXT_L2_ENTRY_2m, NULL, 
   2165                                                   (l2_combo_entry_t *)buf_p);
   2166                         }
   2167                     }
   2168                 } else {
   2169                     /* If the new entry is free then issue del cb */
   2170                     if (soc_mem_field32_get(unit, EXT_L2_ENTRY_2m, buf_p, FREEf)) {
   2171                         callback_suppress = SHR_BITGET(chunk_cb_map_ext2, index);
   2172                         if (!callback_suppress) {
   2173                             soc_l2_entry_callback(unit, 0, EXT_L2_ENTRY_2m, 
   2174                                                   (l2_combo_entry_t *)tab_p_ext2, NULL);
   2175                         }
   2176                     } else {
   2177                         /* If new entry is different then issue a replace (del+ins) cb */
   2178                         delete_marked = SHR_BITGET(chunk_del_map_ext2, index);
   2179                         callback_suppress = SHR_BITGET(chunk_cb_map_ext2, index);
   2180                         if (!(soc->l2x_shadow_hit_bits & L2X_SHADOW_HIT_BITS)) {
   2181                             if (!(soc->l2x_shadow_hit_bits & L2X_SHADOW_HIT_DST)) { 
   2182                                 soc_mem_field32_set(unit, EXT_L2_ENTRY_2m, tab_p_ext2, 
   2183                                     HITDAf, soc_mem_field32_get(unit, 
   2184                                                                 EXT_L2_ENTRY_2m,
   2185                                                                 buf_p, HITDAf));
   2186                             }
   2187                             if (!(soc->l2x_shadow_hit_bits & L2X_SHADOW_HIT_SRC)) {
   2188                                 soc_mem_field32_set(unit, EXT_L2_ENTRY_2m, tab_p_ext2, 
   2189                                     HITSAf, soc_mem_field32_get(unit, 
   2190                                                                 EXT_L2_ENTRY_2m,
   2191                                                                 buf_p, HITSAf));
   2192                             }
   2193                         }
   2194                         if (EXT_L2X_2_ENTRY_EQL(unit, tab_p_ext2, buf_p,
   2195                                                 soc->l2x_shadow_hit_bits)) {
   2196                             if (delete_marked && !callback_suppress) {
   2197                                 soc_l2_entry_callback(unit, 0, EXT_L2_ENTRY_2m,
   2198                                     (l2_combo_entry_t *)tab_p_ext2, NULL);
   2199                             }
   2200                         } else {
   2201                             if (delete_marked && !callback_suppress) {
   2202                                 soc_l2_entry_callback(unit, 0, EXT_L2_ENTRY_2m,
   2203                                     (l2_combo_entry_t *)tab_p_ext2, 
   2204                                     (l2_combo_entry_t *)buf_p);
   2205                             }
   2206                         }
   2207                     }
   2208                 }
   2209                 sal_memcpy(tab_p_ext2, buf_p, tr3_l2x_data[unit].entry_words_ext2 * 4);
   2210                 tab_p_ext2 += tr3_l2x_data[unit].entry_words_ext2;
   2211                 buf_p += tr3_l2x_data[unit].entry_words_ext2;
   2212             }
   2213 
   2214             if ((chunk_index_ext2 += chunk_size_ext2) >= index_count_ext2) {
   2215                 chunk_index_ext2 = 0;
   2216                 tab_p_ext2 = tr3_l2x_data[unit].shadow_tab_ext2;
   2217             }
   2218         }
   2219 continue_loop:
   2220         etime = sal_time_usecs();
   2221 
   2222         /*
   2223          * Implement the sleep using a semaphore timeout so if the task
   2224          * is requested to exit, it can do so immediately.
   2225          */
   2226 
   2227         LOG_VERBOSE(BSL_LS_SOC_ARL,
   2228                     (BSL_META_U(unit,
   2229                                 "soc_l2x_thread: unit=%d: done in %d usec\n"), unit,
   2230                      SAL_USECS_SUB(etime, stime)));
   2231 
   2232         sal_sem_take(soc->l2x_notify, interval / (chunk_count_int ? 
   2233                      chunk_count_int : chunk_count_ext1 ? chunk_count_ext1 :
   2234                      chunk_count_ext2 ? chunk_count_ext2 : 4));
   2235 
   2236         if (!iter) {
   2237             iter++;
   2238         }
   2239     }
   2240 
   2241 cleanup_exit:
   2242     (void)sal_sem_take(soc->l2x_lock, sal_sem_FOREVER);
   2243 
   2244     if (chunk_buf_int != NULL) {
   2245         soc_cm_sfree(unit, chunk_buf_int);
   2246     }
   2247 
   2248     if (shadow_tab != NULL) {
   2249         soc_cm_sfree(unit, shadow_tab);
   2250         shadow_tab = NULL;
   2251     }
   2252 
   2253     if (tr3_l2x_data[unit].shadow_tab_int != NULL) {
   2254         sal_free(tr3_l2x_data[unit].shadow_tab_int);
   2255         tr3_l2x_data[unit].shadow_tab_int = NULL;
   2256     }
   2257 
   2258     if (del_map_int != NULL) {
   2259         sal_free(del_map_int);
   2260         tr3_l2x_data[unit].del_map_int = NULL;
   2261     }
   2262 
   2263     if (chunk_del_map_int != NULL) {
   2264         sal_free(chunk_del_map_int);
   2265     }
   2266 
   2267     if (cb_map_int != NULL) {
   2268         sal_free(cb_map_int);
   2269         tr3_l2x_data[unit].cb_map_int = NULL;
   2270     }
   2271 
   2272     if (chunk_cb_map_int != NULL) {
   2273         sal_free(chunk_cb_map_int);
   2274     }
   2275     
   2276     if (!soc_feature(unit, soc_feature_esm_support)) {
   2277         goto skip_cleanup_l2_ext;
   2278     }
   2279     
   2280     if (chunk_buf_ext1 != NULL) {
   2281         soc_cm_sfree(unit, chunk_buf_ext1);
   2282     }
   2283 
   2284     if (tr3_l2x_data[unit].shadow_tab_ext1 != NULL) {
   2285         sal_free(tr3_l2x_data[unit].shadow_tab_ext1);
   2286         tr3_l2x_data[unit].shadow_tab_ext1 = NULL;
   2287     }
   2288 
   2289     if (del_map_ext1 != NULL) {
   2290         sal_free(del_map_ext1);
   2291         tr3_l2x_data[unit].del_map_ext1 = NULL;
   2292     }
   2293 
   2294     if (chunk_del_map_ext1 != NULL) {
   2295         sal_free(chunk_del_map_ext1);
   2296     }
   2297 
   2298     if (cb_map_ext1 != NULL) {
   2299         sal_free(cb_map_ext1);
   2300         tr3_l2x_data[unit].cb_map_ext1 = NULL;
   2301     }
   2302 
   2303     if (chunk_cb_map_ext1 != NULL) {
   2304         sal_free(chunk_cb_map_ext1);
   2305     }
   2306 
   2307     if (chunk_buf_ext2 != NULL) {
   2308         soc_cm_sfree(unit, chunk_buf_ext2);
   2309     }
   2310 
   2311     if (tr3_l2x_data[unit].shadow_tab_ext2 != NULL) {
   2312         sal_free(tr3_l2x_data[unit].shadow_tab_ext2);
   2313         tr3_l2x_data[unit].shadow_tab_ext2 = NULL;
   2314     }
   2315 
   2316     if (del_map_ext2 != NULL) {
   2317         sal_free(del_map_ext2);
   2318         tr3_l2x_data[unit].del_map_ext2 = NULL;
   2319     }
   2320 
   2321     if (chunk_del_map_ext2 != NULL) {
   2322         sal_free(chunk_del_map_ext2);
   2323     }
   2324 
   2325     if (cb_map_ext2 != NULL) {
   2326         sal_free(cb_map_ext2);
   2327         tr3_l2x_data[unit].cb_map_ext2 = NULL;
   2328     }
   2329 
   2330     if (chunk_cb_map_ext2 != NULL) {
   2331         sal_free(chunk_cb_map_ext2);
   2332     }
   2333 
   2334 skip_cleanup_l2_ext:
   2335     (void)sal_sem_give(soc->l2x_lock);
   2336 
   2337 no_cleanup_exit:
   2338     LOG_INFO(BSL_LS_SOC_ARL,
   2339              (BSL_META_U(unit,
   2340                          "soc_l2x_thread: exiting\n")));
   2341 
   2342     soc->l2x_pid = SAL_THREAD_ERROR;
   2343     sal_thread_exit(0);
   2344 }
   2345 
   2346 void
   2347 soc_tr3_l2mod_fifo_process(int unit, uint32 flags, l2_mod_fifo_entry_t *entry)
   2348 {
   2349     uint32 op;
   2350     soc_mem_t mem_type = INVALIDm;
   2351     uint32 fval[SOC_MAX_MEM_FIELD_WORDS], fval1[SOC_MAX_MEM_FIELD_WORDS];
   2352     l2_combo_entry_t l2_entry, old_l2_entry, temp_l2_entry;
   2353     uint32 key_type;
   2354     int station_move = FALSE;
   2355     int assoc_data_length = 0;
   2356     LOG_VERBOSE(BSL_LS_SOC_ARL,
   2357                 (BSL_META_U(unit,
   2358                             "Processing L2 MOD FIFO message..\n")));
   2359    
   2360     if (soc_L2_MOD_FIFOm_field32_get(unit, entry, EXTERNAL_L2_ENTRYf)) {
   2361         if (soc_feature(unit, soc_feature_esm_support)) {
   2362             if (soc_L2_MOD_FIFOm_field32_get(unit, entry, ENTRY_WIDTHf)) {
   2363                 mem_type = EXT_L2_ENTRY_2m;
   2364                  soc_L2_MOD_FIFOm_field_get(unit, entry, L2_ENTRYf,
   2365                                             l2_entry.ext_l2_entry_2.entry_data);
   2366 
   2367                 LOG_INFO(BSL_LS_SOC_ARL,
   2368                          (BSL_META_U(unit,
   2369                                      "External L2 entry type 2.\n")));
   2370             } else {
   2371                 mem_type = EXT_L2_ENTRY_1m;
   2372                 soc_L2_MOD_FIFOm_field_get(unit, entry, L2_ENTRYf,
   2373                                            l2_entry.ext_l2_entry_1.entry_data);
   2374 
   2375                 LOG_INFO(BSL_LS_SOC_ARL,
   2376                          (BSL_META_U(unit,
   2377                                      "External L2 entry type 1.\n")));
   2378             }            
   2379         } else {
   2380             LOG_ERROR(BSL_LS_SOC_L2,
   2381                       (BSL_META_U(unit,
   2382                                   "Unexpected external L2 entry data in L2 MOD FIFO !!\n")));
   2383         }
   2384     } else {
   2385         if (soc_L2_MOD_FIFOm_field32_get(unit, entry, ENTRY_WIDTHf)) {
   2386             soc_L2_MOD_FIFOm_field_get(unit, entry, L2_ENTRYf,
   2387                                        l2_entry.l2_entry_2.entry_data);
   2388             mem_type = L2_ENTRY_2m;
   2389             LOG_INFO(BSL_LS_SOC_ARL,
   2390                      (BSL_META_U(unit,
   2391                                  "Internal L2 entry type 2.\n")));
   2392         } else {
   2393             soc_L2_MOD_FIFOm_field_get(unit, entry, L2_ENTRYf,
   2394                                        l2_entry.l2_entry_1.entry_data);
   2395             mem_type = L2_ENTRY_1m;
   2396             LOG_INFO(BSL_LS_SOC_ARL,
   2397                      (BSL_META_U(unit,
   2398                                  "Internal L2 entry type 1.\n")));
   2399         }
   2400     }
   2401 
   2402     if (soc_L2_MOD_FIFOm_field32_get(unit, entry, STATION_MOVEf)) {
   2403         if (mem_type == L2_ENTRY_1m) {
   2404             /* following is to handle the reserved bit in the actual l2 entry 
   2405             that does not exist in the mod fifo data so we convert/split the 
   2406             fifo data into l2 entry by copying over parts of fifo data */
   2407             soc_mem_field_get(unit, L2_ENTRY_1m, l2_entry.l2_entry_1.entry_data, KEY_TYPEf,
   2408                               &key_type);
   2409             if (key_type == 0 || key_type == 2) {
   2410                 /*It is only acceptable for Bridge and VFI mode*/
   2411                 sal_memcpy(&old_l2_entry.l2_entry_1, &l2_entry.l2_entry_1, 
   2412                            sizeof(l2_entry.l2_entry_1));
   2413                 soc_L2_MOD_FIFOm_field_get(unit, (uint32 *)entry,
   2414                                            REPLACED_ASSOC_DATAf, fval);
   2415                 soc_mem_field_set(unit, L2_ENTRY_1m, temp_l2_entry.l2_entry_1.entry_data,
   2416                                   L2__DATAf, fval);
   2417                 soc_mem_field_set(unit, L2_ENTRY_1m, old_l2_entry.l2_entry_1.entry_data, 
   2418                                   L2__DATA_Af,
   2419                                   soc_mem_field_get(unit, L2_ENTRY_1m, 
   2420                                                     temp_l2_entry.l2_entry_1.entry_data,
   2421                                                     L2__DATA_Af, fval));
   2422                 soc_mem_field_set(unit, L2_ENTRY_1m, old_l2_entry.l2_entry_1.entry_data, 
   2423                                   L2__DATA_Bf,
   2424                                   soc_mem_field_get(unit, L2_ENTRY_1m, 
   2425                                                     temp_l2_entry.l2_entry_1.entry_data,
   2426                                                     L2__DUMMYf, fval));
   2427             }
   2428         } else if (mem_type == L2_ENTRY_2m) {
   2429             /* following is needed because associated data is not contiguous in 
   2430                l2 double wide entry but it is contiguous in the mod fifo data so 
   2431                we convert/split the fifo data into l2 entry by copying over parts 
   2432                of fifo data */
   2433             sal_memcpy(&old_l2_entry.l2_entry_2, &l2_entry.l2_entry_2, 
   2434                        sizeof(l2_entry.l2_entry_2));
   2435             soc_L2_MOD_FIFOm_field_get(unit, (uint32 *)entry,
   2436                                        REPLACED_ASSOC_DATAf, fval);
   2437             soc_mem_field_set(unit, L2_ENTRY_2m, temp_l2_entry.l2_entry_2.entry_data,
   2438                               L2__DATAf, fval);
   2439             soc_mem_field_set(unit, L2_ENTRY_2m, old_l2_entry.l2_entry_2.entry_data, 
   2440                               L2__DATA_0f,
   2441                               soc_mem_field_get(unit, L2_ENTRY_2m, 
   2442                                                 temp_l2_entry.l2_entry_2.entry_data,
   2443                                                 L2__DATA_0f, fval));
   2444             soc_mem_field_set(unit, L2_ENTRY_2m, old_l2_entry.l2_entry_2.entry_data, 
   2445                               L2__DATA_1_Af,
   2446                               soc_mem_field_get(unit, L2_ENTRY_2m, 
   2447                                                 temp_l2_entry.l2_entry_2.entry_data,
   2448                                                 L2__DUMMY0f, fval));
   2449             soc_mem_field_set(unit, L2_ENTRY_2m, old_l2_entry.l2_entry_2.entry_data, 
   2450                               L2__DATA_1_Bf,
   2451                               soc_mem_field_get(unit, L2_ENTRY_2m, 
   2452                                                 temp_l2_entry.l2_entry_2.entry_data,
   2453                                                 L2__DUMMY1f, fval));
   2454         }
   2455     }
   2456     if (bsl_check(bslLayerSoc, bslSourceDma, bslSeverityVerbose, unit)) {
   2457         soc_mem_entry_dump(unit, L2_MOD_FIFOm, entry, BSL_VERBOSE|BSL_LS_SOC_DMA);
   2458         LOG_VERBOSE(BSL_LS_SOC_DMA, (BSL_META_U(unit, "\n")));
   2459     }
   2460     if (mem_type == INVALIDm) {
   2461         LOG_ERROR(BSL_LS_SOC_L2,
   2462                   (BSL_META_U(unit,
   2463                               "Unable to determine L2 mem type !!\n")));
   2464         return;
   2465     }
   2466     op = soc_L2_MOD_FIFOm_field32_get(unit, entry, OPERATIONf);
   2467     if ((op == 2 || op == 6 || op == 8) &&
   2468         (mem_type == EXT_L2_ENTRY_1m || mem_type == EXT_L2_ENTRY_2m)) {
   2469         (void)soc_triumph3_ext_l2_entry_update(unit, mem_type,
   2470                   soc_L2_MOD_FIFOm_field32_get(unit, entry, ENTRY_ADRf),
   2471                   (op == 2) ? &l2_entry : NULL);
   2472     }
   2473 
   2474     switch (op) {
   2475     case 0: /* L2_DELETE */
   2476     case 6: /* L2_BULK_DELETE */
   2477     case 8: /* L2_BULK_AGE */
   2478         soc_l2_entry_callback(unit, 0, mem_type, &l2_entry, NULL);
   2479         break;
   2480     case 7: /* L2_BULK_REPLACE */
   2481         soc_l2_entry_callback(unit, 0, mem_type, &l2_entry, &l2_entry);
   2482         break;
   2483     case 1: /* L2_INSERT */
   2484     case 2: /* LEARN */
   2485         if (soc_L2_MOD_FIFOm_field32_get(unit, entry, STATION_MOVEf)) {
   2486             /* The following is a workaround for L2_MOD_FIFO. The false callback caused 
   2487                by false staion move is avoided. */
   2488             if (mem_type == L2_ENTRY_1m) {
   2489                 assoc_data_length = BITS2BYTES(soc_mem_field_length(unit, L2_ENTRY_1m, 
   2490                                                          L2__DATAf));
   2491                 soc_L2_MOD_FIFOm_field_get(unit, (uint32 *)entry,
   2492                                            REPLACED_ASSOC_DATAf, fval);
   2493                 soc_mem_field_get(unit, L2_ENTRY_1m, l2_entry.l2_entry_1.entry_data,
   2494                                   L2__DATAf, fval1);
   2495                 station_move = sal_memcmp(fval1, fval, assoc_data_length);
   2496                     
   2497             } else if (mem_type == L2_ENTRY_2m) {
   2498                 assoc_data_length = BITS2BYTES(soc_mem_field_length(unit, L2_ENTRY_2m, 
   2499                                                          L2__DATAf));
   2500                 soc_L2_MOD_FIFOm_field_get(unit, (uint32 *)entry,
   2501                                            REPLACED_ASSOC_DATAf, fval);
   2502                 soc_mem_field_get(unit, L2_ENTRY_2m, l2_entry.l2_entry_2.entry_data,
   2503                                   L2__DATAf, fval1);
   2504                 station_move = sal_memcmp(fval1, fval, assoc_data_length);
   2505 
   2506             } else if (mem_type == EXT_L2_ENTRY_1m) {
   2507                 assoc_data_length = BITS2BYTES(soc_mem_field_length(unit, EXT_L2_ENTRY_1m, 
   2508                                                                     DATAf));
   2509                 soc_L2_MOD_FIFOm_field_get(unit, (uint32 *)entry,
   2510                                            REPLACED_ASSOC_DATAf, fval);
   2511                 soc_mem_field_get(unit, EXT_L2_ENTRY_1m, l2_entry.ext_l2_entry_1.entry_data,
   2512                                   DATAf, fval1);
   2513                 station_move = sal_memcmp(fval1, fval, assoc_data_length);               
   2514             } else if (mem_type == EXT_L2_ENTRY_2m) {
   2515                 assoc_data_length = BITS2BYTES(soc_mem_field_length(unit, EXT_L2_ENTRY_2m, 
   2516                                                                     DATAf));
   2517                 soc_L2_MOD_FIFOm_field_get(unit, (uint32 *)entry,
   2518                                            REPLACED_ASSOC_DATAf, fval);
   2519                 soc_mem_field_get(unit, EXT_L2_ENTRY_2m, l2_entry.ext_l2_entry_2.entry_data,
   2520                                   DATAf, fval1);
   2521                 station_move = sal_memcmp(fval1, fval, assoc_data_length);                
   2522             }
   2523             if (station_move) {
   2524                 soc_l2_entry_callback(unit, 0, mem_type, &old_l2_entry, &l2_entry);
   2525             }
   2526 	} else {
   2527             soc_l2_entry_callback(unit, 0, mem_type, NULL, &l2_entry);
   2528         }
   2529         break;
   2530     default:
   2531         break;
   2532     }
   2533     if (bsl_check(bslLayerSoc, bslSourceDma, bslSeverityVerbose, unit)) {
   2534         soc_mem_entry_dump(unit, L2_MOD_FIFOm, entry, BSL_VERBOSE|BSL_LS_SOC_DMA);
   2535         LOG_VERBOSE(BSL_LS_SOC_DMA, (BSL_META_U(unit, "\n")));
   2536     }
   2537 }
   2538 
   2539 int
   2540 soc_tr3_l2_overflow_entry_get(int unit, l2_combo_entry_t *entry, soc_mem_t *mem_type)
   2541 {
   2542     SOC_IF_ERROR_RETURN
   2543         (READ_L2_LEARN_INSERT_FAILUREm(unit, COPYNO_ALL, 0, entry->words));
   2544     if (soc_L2_ENTRY_1m_field32_get(unit, entry->words, WIDEf)) {
   2545         *mem_type = L2_ENTRY_2m;
   2546     } else {
   2547         *mem_type = L2_ENTRY_1m;
   2548     }
   2549     return SOC_E_NONE;
   2550 }
   2551 
   2552 int
   2553 soc_tr3_l2_overflow_disable(int unit)
   2554 {
   2555     SOC_IF_ERROR_RETURN
   2556         (soc_reg_field32_modify(unit, ISM_INTR_MASKr, REG_PORT_ANY,
   2557                                 L2_LEARN_INSERT_FAILUREf, 0));
   2558     /* Mark as inactive */
   2559     SOC_CONTROL_LOCK(unit);
   2560     SOC_CONTROL(unit)->l2_overflow_active = FALSE;
   2561     SOC_CONTROL_UNLOCK(unit);
   2562     /* But don't disable interrupt as its shared by various ISM events */
   2563     return SOC_E_NONE;
   2564 }
   2565 
   2566 int
   2567 soc_tr3_l2_overflow_enable(int unit)
   2568 {
   2569     SOC_IF_ERROR_RETURN
   2570         (soc_reg_field32_modify(unit, ISM_INTR_MASKr, REG_PORT_ANY,
   2571                                 L2_LEARN_INSERT_FAILUREf, 1));
   2572     /* Mark as active */
   2573     SOC_CONTROL_LOCK(unit);
   2574     SOC_CONTROL(unit)->l2_overflow_active = TRUE;
   2575     SOC_CONTROL_UNLOCK(unit);
   2576     /* Enable interrupt */
   2577 #ifdef BCM_CMICM_SUPPORT
   2578     (void)soc_cmicm_intr1_enable(unit, _SOC_TR3_ISM_INTR_MASK);
   2579 #endif
   2580     return SOC_E_NONE;
   2581 }
   2582 
   2583 int
   2584 soc_tr3_l2_overflow_fill(int unit, uint8 zeros_or_ones)
   2585 {
   2586     l2_learn_insert_failure_entry_t entry;
   2587     
   2588     if (zeros_or_ones) {
   2589         sal_memset(&entry, 0xffffffff, sizeof(entry));
   2590         SOC_IF_ERROR_RETURN
   2591             (WRITE_L2_LEARN_INSERT_FAILUREm(unit, COPYNO_ALL, 0, &entry));
   2592     } else {
   2593         SOC_IF_ERROR_RETURN
   2594             (soc_mem_clear(unit, L2_LEARN_INSERT_FAILUREm, COPYNO_ALL, FALSE));
   2595     }    
   2596     return SOC_E_NONE;
   2597 }
   2598 
   2599 void
   2600 soc_tr3_l2_overflow_interrupt_handler(int unit)
   2601 {
   2602     l2_combo_entry_t entry;
   2603     soc_mem_t mem_type = INVALIDm;
   2604 
   2605     if (!SOC_CONTROL(unit)->l2_overflow_active) {
   2606         LOG_ERROR(BSL_LS_SOC_L2, \
   2607                   (BSL_META_U(unit, \
   2608                               "Received L2 overflow event with no app handler or"\
   2609                               " processing inactive !!\n")));
   2610     }
   2611     if (soc_tr3_l2_overflow_disable(unit)) {
   2612         return;
   2613     }
   2614     if (soc_tr3_l2_overflow_entry_get(unit, &entry, &mem_type)) {
   2615         return;
   2616     }
   2617     if (mem_type == INVALIDm) {
   2618         return;
   2619     }
   2620     /* Callback */
   2621     soc_l2_entry_callback(unit, SOC_L2X_ENTRY_OVERFLOW, mem_type, NULL, &entry);
   2622 }
   2623 
   2624 int
   2625 soc_tr3_l2_overflow_stop(int unit)
   2626 {
   2627     if (!SOC_CONTROL(unit)->l2_overflow_enable) {
   2628         return SOC_E_NONE;
   2629     }
   2630     SOC_IF_ERROR_RETURN(soc_tr3_l2_overflow_fill(unit, 1));
   2631     SOC_IF_ERROR_RETURN(soc_tr3_l2_overflow_disable(unit));
   2632     return SOC_E_NONE;
   2633 }
   2634 
   2635 int
   2636 soc_tr3_l2_overflow_start(int unit)
   2637 {
   2638     if (!SOC_CONTROL(unit)->l2_overflow_enable) {
   2639         return SOC_E_NONE;
   2640     }
   2641     if (SOC_CONTROL(unit)->l2_overflow_active) {
   2642         return SOC_E_NONE;
   2643     }
   2644     SOC_IF_ERROR_RETURN(soc_tr3_l2_overflow_fill(unit, 0));
   2645     SOC_IF_ERROR_RETURN(soc_tr3_l2_overflow_enable(unit));
   2646     return SOC_E_NONE;
   2647 }
   2648 
   2649 /*
   2650  * External L2 Bulk Delete/Replace Acceleration
   2651  *
   2652  * Hardware scanning of the external L2 table for bulk delete and
   2653  * bulk replace can be a little slow with large L2 tables.  This
   2654  * code caches enough information on each entry in order to do a
   2655  * quick software walk of the table looking for matches.
   2656  *
   2657  * There are per-vlan min and max indices that are kept so that for
   2658  * per-vlan or per-vlan/port scans we only need to look at a subset of
   2659  * the entries.
   2660  */
   2661 STATIC int
   2662 _soc_tr3_l2e_ppa_init(int unit)
   2663 {
   2664     _soc_tr3_l2e_ppa_info_t *einfo;
   2665     _soc_tr3_l2e_ppa_vlan_t *evlan;
   2666     int                     vlan, esize;
   2667 
   2668     if (SOC_CONTROL(unit)->ext_l2_ppa_info != NULL) {
   2669         sal_free(SOC_CONTROL(unit)->ext_l2_ppa_info);
   2670         SOC_CONTROL(unit)->ext_l2_ppa_info = NULL;
   2671     }
   2672     if (SOC_CONTROL(unit)->ext_l2_ppa_vlan != NULL) {
   2673         sal_free(SOC_CONTROL(unit)->ext_l2_ppa_vlan);
   2674         SOC_CONTROL(unit)->ext_l2_ppa_vlan = NULL;
   2675     }
   2676     if (SOC_CONTROL(unit)->ext_l2_ppa_info_2 != NULL) {
   2677         sal_free(SOC_CONTROL(unit)->ext_l2_ppa_info_2);
   2678         SOC_CONTROL(unit)->ext_l2_ppa_info_2 = NULL;
   2679     }
   2680     if (SOC_CONTROL(unit)->ext_l2_ppa_vlan_2 != NULL) {
   2681         sal_free(SOC_CONTROL(unit)->ext_l2_ppa_vlan_2);
   2682         SOC_CONTROL(unit)->ext_l2_ppa_vlan_2 = NULL;
   2683     }
   2684 
   2685     /* EXT_L2_ENTRY_1 */
   2686     esize = soc_mem_index_count(unit, EXT_L2_ENTRY_1m) *
   2687                 sizeof(_soc_tr3_l2e_ppa_info_t);
   2688     einfo = sal_alloc(esize, "_soc_tr3_l2e_ppa_info 1");
   2689     if (einfo == NULL) {
   2690         return SOC_E_MEMORY;
   2691     }
   2692 
   2693     evlan = sal_alloc(sizeof(_soc_tr3_l2e_ppa_vlan_t),
   2694                       "_soc_tr3_l2e_ppa_vlan 1");
   2695     if (evlan == NULL) {
   2696         sal_free(einfo);
   2697         return SOC_E_MEMORY;
   2698     }
   2699     sal_memset(einfo, 0, esize);
   2700     for (vlan = 0; vlan <= VLAN_ID_MAX; vlan++) {
   2701         evlan->vlan_min[vlan] = -1;
   2702         evlan->vlan_max[vlan] = -1;
   2703     }
   2704     SOC_CONTROL(unit)->ext_l2_ppa_info = einfo;
   2705     SOC_CONTROL(unit)->ext_l2_ppa_vlan = evlan;
   2706     
   2707     /* EXT_L2_ENTRY_2 */
   2708     esize = soc_mem_index_count(unit, EXT_L2_ENTRY_2m) *
   2709                 sizeof(_soc_tr3_l2e_ppa_info_t);
   2710     einfo = sal_alloc(esize, "_soc_tr3_l2e_ppa_info 2");
   2711     if (einfo == NULL) {
   2712         return SOC_E_MEMORY;
   2713     }
   2714     evlan = sal_alloc(sizeof(_soc_tr3_l2e_ppa_vlan_t),
   2715                       "_soc_tr3_l2e_ppa_vlan 2");
   2716     if (evlan == NULL) {
   2717         sal_free(einfo);
   2718         return SOC_E_MEMORY;
   2719     }
   2720     sal_memset(einfo, 0, esize);
   2721     for (vlan = 0; vlan <= VLAN_ID_MAX; vlan++) {
   2722         evlan->vlan_min[vlan] = -1;
   2723         evlan->vlan_max[vlan] = -1;
   2724     }
   2725     SOC_CONTROL(unit)->ext_l2_ppa_info_2 = einfo;
   2726     SOC_CONTROL(unit)->ext_l2_ppa_vlan_2 = evlan;
   2727     
   2728     SOC_CONTROL(unit)->ext_l2_ppa_threshold = 
   2729         soc_property_get(unit, spn_EXT_L2_USE_HARDWARE_REPLACE_THRESHOLD, 
   2730                          10000);
   2731     
   2732     return SOC_E_NONE;
   2733 }
   2734 
   2735 STATIC int
   2736 _soc_tr3_l2e_ppa_update(int unit, soc_mem_t mem, int index, uint32 *entry)
   2737 {
   2738     _soc_tr3_l2e_ppa_info_t *ppa_info;
   2739     _soc_tr3_l2e_ppa_vlan_t *ppa_vlan;
   2740     uint32      entvalue;
   2741     uint32      l2data;
   2742     sal_mac_addr_t   l2mac;
   2743     vlan_id_t   vlan, oldvlan;
   2744     int         vlan_min, vlan_max;
   2745     uint32      vdata, vmask;
   2746 
   2747     if (SOC_CONTROL(unit)->ext_l2_ppa_info == NULL) {
   2748         if (!soc_mem_is_valid(unit, mem) ||
   2749             soc_mem_index_count(unit, mem) <= 0) {
   2750             return SOC_E_NONE;
   2751         }
   2752         SOC_IF_ERROR_RETURN(_soc_tr3_l2e_ppa_init(unit));
   2753     }
   2754 
   2755     ppa_info = SOC_CONTROL(unit)->ext_l2_ppa_info;
   2756     ppa_vlan = SOC_CONTROL(unit)->ext_l2_ppa_vlan;
   2757 
   2758     vlan = 0;
   2759     entvalue = 0;
   2760     if (entry != NULL) {
   2761         l2data = soc_mem_field32_get(unit, mem, entry, FREEf);
   2762         if (l2data != 1) {
   2763             entvalue |= _SOC_TR3_L2E_VALID;
   2764         }
   2765         l2data = soc_mem_field32_get(unit, mem, entry, STATIC_BITf);
   2766         if (l2data != 0) {
   2767             entvalue |= _SOC_TR3_L2E_STATIC;
   2768         }
   2769         l2data = soc_mem_field32_get(unit, mem, entry, VLAN_IDf);
   2770         vlan = l2data;
   2771         entvalue |= (l2data & _SOC_TR3_L2E_VLAN_MASK) << _SOC_TR3_L2E_VLAN_SHIFT;
   2772         if (soc_mem_field32_get(unit, mem, entry, DEST_TYPEf) == 0x1) {
   2773             l2data = soc_mem_field32_get(unit, mem, entry, TGIDf);
   2774             entvalue |= _SOC_TR3_L2E_T |
   2775                 ((l2data & _SOC_TR3_L2E_TRUNK_MASK) << _SOC_TR3_L2E_TRUNK_SHIFT);
   2776         } else if (soc_mem_field32_get(unit, mem, entry, DEST_TYPEf) == 0x2) {
   2777             l2data = soc_mem_field32_get(unit, mem, entry, DESTINATIONf);
   2778             entvalue |= _SOC_TR3_L2E_VP |
   2779                 ((l2data & _SOC_TR3_L2E_DESTINATION_MASK) << 
   2780                  _SOC_TR3_L2E_DESTINATION_SHIFT);
   2781         } else {
   2782             l2data = soc_mem_field32_get(unit, mem, entry, MODULE_IDf);
   2783             entvalue |=
   2784                 (l2data & _SOC_TR3_L2E_MOD_MASK) << _SOC_TR3_L2E_MOD_SHIFT;
   2785             l2data = soc_mem_field32_get(unit, mem, entry, PORT_NUMf);
   2786             entvalue |=
   2787                 (l2data & _SOC_TR3_L2E_PORT_MASK) << _SOC_TR3_L2E_PORT_SHIFT;
   2788         }
   2789         soc_mem_mac_addr_get(unit, mem, entry, MAC_ADDRf, l2mac);
   2790     } else {
   2791         sal_memset(l2mac, 0, sizeof(l2mac));
   2792     }
   2793     oldvlan = (ppa_info[index].data >> 16) & 0xfff;
   2794     ppa_info[index].data = entvalue;
   2795     sal_memcpy(ppa_info[index].mac, l2mac, sizeof(sal_mac_addr_t));
   2796 
   2797     if (vlan != oldvlan) {      /* update vlan_min/max indices */
   2798         if (oldvlan != 0) {
   2799             vlan_min = ppa_vlan->vlan_min[oldvlan];
   2800             vlan_max = ppa_vlan->vlan_max[oldvlan];
   2801             vdata = oldvlan << _SOC_TR3_L2E_VLAN_SHIFT;
   2802             vmask = _SOC_TR3_L2E_VLAN_MASK << _SOC_TR3_L2E_VLAN_SHIFT;
   2803 
   2804             /* deleted last one? */
   2805             if (index == vlan_min && index == vlan_max) {
   2806                 ppa_vlan->vlan_min[oldvlan] = -1;
   2807                 ppa_vlan->vlan_max[oldvlan] = -1;
   2808             } else if (index == vlan_min) {
   2809                 for (; vlan_min <= vlan_max; vlan_min++) {
   2810                     entvalue = ppa_info[vlan_min].data;
   2811                     if ((entvalue & vmask) == vdata) {
   2812                         break;
   2813                     }
   2814                 }
   2815                 ppa_vlan->vlan_min[oldvlan] = vlan_min;
   2816             } else if (index == vlan_max) {
   2817                 for (; vlan_min <= vlan_max; vlan_max--) {
   2818                     entvalue = ppa_info[vlan_max].data;
   2819                     if ((entvalue & vmask) == vdata) {
   2820                         break;
   2821                     }
   2822                 }
   2823                 ppa_vlan->vlan_max[oldvlan] = vlan_max;
   2824             }
   2825 
   2826         }
   2827         if (vlan != 0) {
   2828             vlan_min = ppa_vlan->vlan_min[vlan];
   2829             vlan_max = ppa_vlan->vlan_max[vlan];
   2830             if (vlan_min < 0 || index < vlan_min) {
   2831                 ppa_vlan->vlan_min[vlan] = index;
   2832             }
   2833             if (vlan_max < 0 || index > vlan_max) {
   2834                 ppa_vlan->vlan_max[vlan] = index;
   2835             }
   2836         }
   2837     }
   2838 
   2839     LOG_VERBOSE(BSL_LS_SOC_COMMON,
   2840                 (BSL_META_U(unit,
   2841                             "tr3_l2e_ppa %d: index=%d oldvlan=%d min:max %d:%d\n"),
   2842                  mem == EXT_L2_ENTRY_1m ? 1 : 2,
   2843                  index, oldvlan, ppa_vlan->vlan_min[oldvlan],
   2844                  ppa_vlan->vlan_max[oldvlan]));
   2845     LOG_VERBOSE(BSL_LS_SOC_COMMON,
   2846                 (BSL_META_U(unit,
   2847                             "tr3_l2e_ppa %d: ent=0x%x mac=%x:%x:%x:%x:%x:%x "
   2848                             "vlan=%d min:max %d:%d\n"),
   2849                  mem == EXT_L2_ENTRY_1m ? 1 : 2,
   2850                  ppa_info[index].data,
   2851                  l2mac[0], l2mac[1], l2mac[2], l2mac[3], l2mac[4], l2mac[5],
   2852                  vlan, ppa_vlan->vlan_min[vlan],
   2853                  ppa_vlan->vlan_max[vlan]));
   2854     return SOC_E_NONE;
   2855 }
   2856 
   2857 int
   2858 soc_triumph3_ext_l2_entry_update(int unit, soc_mem_t mem, int index, void *entry)
   2859 {
   2860     return _soc_tr3_l2e_ppa_update(unit, mem, index, entry);
   2861 }
   2862 
   2863 #endif /* BCM_TRIUMPH3_SUPPORT */