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


      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 <shared/bsl.h>
     20 #include <sal/core/spl.h>
     21 #include <sal/core/time.h>
     22 
     23 #include <soc/mem.h>
     24 #include <soc/debug.h>
     25 #include <soc/cm.h>
     26 #include <soc/drv.h>
     27 #include <soc/l2x.h>
     28 #if defined(BCM_TRIDENT2_SUPPORT)
     29 #include <soc/trident2.h>
     30 #endif
     31 #if defined(BCM_TOMAHAWK_SUPPORT)
     32 #include <soc/tomahawk.h>
     33 #endif
     34 #if defined(BCM_MONTEREY_SUPPORT)
     35 #include <soc/monterey.h>
     36 #endif
     37 #if defined(BCM_APACHE_SUPPORT)
     38 #include <soc/apache.h>
     39 #endif
     40 #if defined(BCM_HURRICANE3_SUPPORT)
     41 #include <soc/hurricane3.h>
     42 #endif
     43 #if defined(BCM_TOMAHAWK3_SUPPORT)
     44 #include <soc/tomahawk3.h>
     45 #endif
     46 #ifdef BCM_XGS_SWITCH_SUPPORT
     47 
     48 #define L2X_ENTRY_EQL(unit, e1, e2, sz, bits) \
     49     (!_soc_mem_cmp_l2x_sync(unit, (void *) e1, (void *) e2, sz, bits))
     50 
     51 #define L2X_IS_VALID_ENTRY(_u, _mem, _e, bitf)  \
     52            soc_mem_field32_get((_u), (_mem), (_e), bitf)
     53 
     54 #ifdef BCM_TRIUMPH3_SUPPORT
     55 extern int
     56 soc_tr3_l2x_running(int unit, uint32 *flags, sal_usecs_t *interval);
     57 extern int
     58 soc_tr3_l2x_start(int unit, uint32 flags, sal_usecs_t interval);
     59 extern int
     60 soc_tr3_l2x_stop(int unit);
     61 #endif
     62 
     63 STATIC void _soc_l2x_thread(void *unit_vp);
     64 
     65 /****************************************************************************
     66  *
     67  * L2X Message Registration
     68  */
     69 
     70 #define L2X_CB_MAX      3
     71 
     72 typedef struct l2x_cb_entry_s {
     73     soc_l2x_cb_fn       fn;
     74     void                *fn_data;
     75 } l2x_cb_entry_t;
     76 
     77 typedef struct l2x_data_s {
     78     l2x_cb_entry_t              cb[L2X_CB_MAX];
     79     int                         cb_count;
     80     soc_mem_t                   l2mem;
     81     int                         entry_bytes;
     82     int                         entry_words;
     83     uint32                      *shadow_tab;
     84     uint32                      *chunk_buf;
     85     SHR_BITDCL                  *delete_map;
     86     SHR_BITDCL                  *callback_map;
     87     SHR_BITDCL                  *sr_ref_map;
     88 } l2x_data_t;
     89 
     90 STATIC l2x_data_t l2x_data[SOC_MAX_NUM_DEVICES];
     91 
     92 #define L2X_ENTRY_CALLBACK_SET(_u_, _index_)                \
     93 {                                                           \
     94     SHR_BITSET(l2x_data[(_u_)].callback_map, (_index_));    \
     95     LOG_VERBOSE(BSL_LS_SOC_ARL, \
     96                 (BSL_META_U(unit, \
     97                             "set_entry_callback: u:%d i=%d\n"), \
     98                             _u_, _index_));                             \
     99 }
    100 
    101 #define L2X_ENTRY_DELETED_SET(_u_, _index_)                 \
    102 {                                                           \
    103     SHR_BITSET(l2x_data[(_u_)].delete_map, (_index_));      \
    104     LOG_VERBOSE(BSL_LS_SOC_ARL, \
    105                 (BSL_META_U(unit, \
    106                             "set_entry_deleted: u:%d i=%d\n"),  \
    107                             _u_, _index_));                             \
    108 }
    109 
    110 #define L2X_IS_CPU_DELETED(_u_, _index_)                    \
    111             SHR_BITGET(l2x_data[(_u_)].delete_map, (_index_))
    112 
    113 #define SOC_L2X_TGID_TRUNK_INDICATOR(unit) \
    114         SOC_IS_RAVEN(unit) ? 0x40 : 0x20
    115 #define SOC_L2X_TGID_PORT_TRUNK_MASK           0x1f
    116 #define SOC_L2X_TGID_PORT_TRUNK_MASK_HI        0x60
    117 
    118 /* Get L2x mode from soc property */
    119 int
    120 soc_l2x_mode_cfg_get(int unit)
    121 {
    122     int mode, def_mode = L2MODE_POLL;
    123 
    124     if (!(SAL_BOOT_BCMSIM || SAL_BOOT_XGSSIM) &&
    125         soc_feature(unit, soc_feature_l2_modfifo) &&
    126         soc_feature(unit, soc_feature_l2_modfifo_def)) {
    127         def_mode = L2MODE_FIFO;
    128     }
    129 
    130     mode = soc_property_get(unit, spn_L2XMSG_MODE, def_mode);
    131 
    132     return mode;
    133 }
    134 
    135 /*
    136  * Function:
    137  *	soc_l2x_register
    138  * Purpose:
    139  *	Register a callback routine to be notified of all inserts,
    140  *	deletes, and updates to the L2X table.
    141  * Parameters:
    142  *	unit - StrataSwitch unit number
    143  *	fn - Callback function to register
    144  *	fn_data - Extra data passed to callback function
    145  * Returns:
    146  *	SOC_E_NONE - Success
    147  *	SOC_E_MEMORY - Too many callbacks registered
    148  */
    149 
    150 int
    151 soc_l2x_register(int unit, soc_l2x_cb_fn fn, void *fn_data)
    152 {
    153     l2x_data_t      *ad = &l2x_data[unit];
    154     int                 i;
    155 #ifdef BCM_XGS3_SWITCH_SUPPORT
    156     soc_control_t	*soc = SOC_CONTROL(unit);
    157     int                 mode;
    158 
    159     mode = soc_l2x_mode_cfg_get(unit);
    160 
    161     if ((mode == L2MODE_FIFO) && !soc_feature(unit, soc_feature_l2_modfifo)) {
    162         mode = L2MODE_POLL;
    163     }
    164 
    165     if ((mode == L2MODE_POLL) && soc->l2x_external) {
    166         /* Not supported for external L2 memory configuration. */
    167         return SOC_E_UNAVAIL;
    168     }
    169 #endif
    170     if (!soc_feature(unit, soc_feature_arl_hashed)) {
    171         return SOC_E_UNAVAIL;
    172     }
    173 
    174     if (ad->cb_count >= L2X_CB_MAX) {
    175         return SOC_E_MEMORY;
    176     }
    177 
    178     for (i = 0; i < ad->cb_count; i++) {
    179         if ((ad->cb[i].fn == fn &&
    180              ad->cb[i].fn_data == fn_data)) {
    181             return SOC_E_NONE; /* Already registered */
    182         }
    183     }
    184 
    185     ad->cb[ad->cb_count].fn = fn;
    186     ad->cb[ad->cb_count].fn_data = fn_data;
    187 
    188     ad->cb_count++;
    189 
    190     return SOC_E_NONE;
    191 }
    192 
    193 /*
    194  * Function:
    195  *	soc_l2x_unregister
    196  * Purpose:
    197  *  Unregister a callback routine; requires same args as when registered
    198  * Parameters:
    199  *  unit - StrataSwitch unit number
    200  *  fn - Callback function to unregister; NULL to unregister all
    201  *  fn_data - Extra data passed to callback function;
    202  *  must match registered value unless fn is NULL
    203  * Returns:
    204  *  SOC_E_NONE - Success
    205  *  SOC_E_NOT_FOUND - Matching registered routine not found
    206  */
    207 
    208 int
    209 soc_l2x_unregister(int unit, soc_l2x_cb_fn fn, void *fn_data)
    210 {
    211     l2x_data_t  *ad = &l2x_data[unit];
    212     int         i;
    213     if (fn == NULL) {
    214         ad->cb_count = 0;
    215         return SOC_E_NONE;
    216     }
    217 
    218     for (i = 0; i < ad->cb_count; i++) {
    219         if ((ad->cb[i].fn == fn &&
    220              ad->cb[i].fn_data == fn_data)) {
    221 
    222             for (ad->cb_count--; i < ad->cb_count; i++) {
    223                 sal_memcpy(&ad->cb[i], &ad->cb[i + 1],
    224                            sizeof (l2x_cb_entry_t));
    225             }
    226 
    227             return SOC_E_NONE;
    228         }
    229     }
    230 
    231     return SOC_E_NOT_FOUND;
    232 }
    233 
    234 /*
    235  * Function:
    236  *	soc_l2x_callback
    237  * Purpose:
    238  *	Routine to execute all callbacks on the list.
    239  * Parameters:
    240  *	unit - unit number.
    241  *	entry_del - deleted or updated entry, NULL if none.
    242  *	entry_add - added or updated entry, NULL if none.
    243  */
    244 
    245 void
    246 soc_l2x_callback(int unit, int flags, l2x_entry_t *entry_del, l2x_entry_t *entry_add)
    247 {
    248     l2x_data_t      *ad = &l2x_data[unit];
    249     int         i;
    250     for (i = 0; i < ad->cb_count; i++) {
    251         (*ad->cb[i].fn)(unit, flags, entry_del, entry_add, ad->cb[i].fn_data);
    252     }
    253 }
    254 
    255 /*
    256  * Function:
    257  * 	soc_l2x_running
    258  * Purpose:
    259  *	Determine the L2X sync thread running parameters
    260  * Parameters:
    261  *	unit - unit number.
    262  *	flags (OUT) - if non-NULL, receives the current flag settings
    263  *	interval (OUT) - if non-NULL, receives the current pass interval
    264  * Returns:
    265  *   	Boolean; TRUE if L2X sync thread is running
    266  */
    267 
    268 int
    269 soc_l2x_running(int unit, uint32 *flags, sal_usecs_t *interval)
    270 {
    271     soc_control_t   *soc = SOC_CONTROL(unit);
    272 #ifdef BCM_TRIUMPH3_SUPPORT
    273     if SOC_IS_TRIUMPH3(unit) {
    274         return soc_tr3_l2x_running(unit, flags, interval);
    275     }
    276 #endif
    277     if (soc->l2x_pid != SAL_THREAD_ERROR) {
    278         if (flags != NULL) {
    279             *flags = soc->l2x_flags;
    280         }
    281         if (interval != NULL) {
    282             *interval = soc->l2x_interval;
    283         }
    284     }
    285 
    286     return(soc->l2x_pid != SAL_THREAD_ERROR);
    287 }
    288 
    289 /* It only can handle delete so far */
    290 int
    291 _soc_l2x_sync_replace(int unit, l2x_entry_t *l2x_match_data,
    292                       l2x_entry_t *l2x_match_mask, uint32 flags)
    293 {
    294     soc_control_t *soc = SOC_CONTROL(unit);
    295     uint32 *entry, *match_data, *match_mask;
    296     int index_max, entry_words, idx, i;
    297 
    298     if (soc->l2x_pid == SAL_THREAD_ERROR) {
    299         /* thread not running */
    300         return SOC_E_NONE;
    301     }
    302 
    303     entry = l2x_data[unit].shadow_tab;
    304     if (entry == NULL) {
    305         return SOC_E_NONE;
    306     }
    307     match_data = (uint32 *)l2x_match_data;
    308     match_mask = (uint32 *)l2x_match_mask;
    309 
    310     index_max = soc_mem_index_max(unit, L2Xm);
    311     entry_words = soc_mem_entry_words(unit, L2Xm);
    312 
    313     (void)sal_sem_take(soc->l2x_lock, sal_sem_FOREVER);
    314 
    315     for (idx = 0; idx <= index_max; idx++, entry += entry_words) {
    316         for (i = 0; i < entry_words; i++) {
    317             if ((entry[i] ^ match_data[i]) & match_mask[i]) {
    318                 break;
    319             }
    320         }
    321         if (i != entry_words) {
    322             continue;
    323         }
    324         soc_l2x_sync_delete(unit, entry, idx, flags);
    325     }
    326 
    327     (void)sal_sem_give(soc->l2x_lock);
    328 
    329     return SOC_E_NONE;
    330 }
    331  
    332 /*
    333  * Function:
    334  * 	_soc_l2x_sync_delete_by
    335  * Purpose:
    336  *	Search all the entries in the shadow table based on the 
    337  *	criteria and mark them as deleted.
    338  * Parameters:
    339  * Returns:
    340  *      SOC_E_XX
    341  */
    342 int
    343 _soc_l2x_sync_delete_by(int unit, uint32 mod, uint32 port,
    344                         uint16 vid, uint32 tid, int vfi,
    345                         uint32 flags, uint32 search_key)
    346 {
    347     soc_control_t   *soc = SOC_CONTROL(unit);
    348     int             index, max_index, stl2;
    349     uint32          *entry = NULL;
    350     soc_field_t     valid_bit = VALIDf;
    351     int             trunk128, rv = SOC_E_NONE;
    352     int             static_bit_val;
    353     uint32          tgid_hi = 0, tgid_lo = 0;
    354     uint32          tgid_val, port_val, mod_id;
    355     vlan_id_t       vlan_id;
    356 
    357 #ifdef BCM_TRIUMPH3_SUPPORT
    358     if SOC_IS_TRIUMPH3(unit) {
    359         return _soc_tr3_l2x_sync_delete_by(unit, mod, port, vid, tid, vfi,
    360                                            flags, search_key);
    361     }
    362 #endif 
    363 
    364 
    365     if (soc->l2x_pid == SAL_THREAD_ERROR) {
    366         /* thread not running */
    367         return SOC_E_NONE;
    368     }
    369 
    370     max_index = soc_mem_index_max(unit, l2x_data[unit].l2mem);
    371 
    372     stl2 = (flags & SOC_L2X_INC_STATIC) ? 1 : 0;
    373 
    374     (void)sal_sem_take(soc->l2x_lock, sal_sem_FOREVER);
    375 
    376     entry = l2x_data[unit].shadow_tab;
    377     if (!entry) {
    378         goto exit;
    379     }
    380 
    381     if (search_key == SOC_L2X_PORTMOD_DEL) {
    382         for (index = 0; index < max_index; index++,
    383             entry += l2x_data[unit].entry_words) {
    384             if (!L2X_IS_VALID_ENTRY(unit, l2x_data[unit].l2mem, 
    385                                     entry, valid_bit)) {
    386                 continue;
    387             }
    388             if (soc_feature(unit, soc_feature_trunk_group_overlay)) {
    389                 if (soc_mem_field32_get(unit, l2x_data[unit].l2mem, entry,
    390                                         Tf)) {
    391                     continue;
    392                 }
    393                 port_val = soc_mem_field32_get(unit, l2x_data[unit].l2mem,
    394                                                entry, PORT_NUMf);
    395             } else {
    396                 port_val = soc_mem_field32_get(unit, l2x_data[unit].l2mem,
    397                                                entry, TGID_PORTf);
    398             }
    399             mod_id = soc_mem_field32_get(unit, l2x_data[unit].l2mem,
    400                                          entry, MODULE_IDf);
    401             if ((port != port_val) || (mod != mod_id)) {
    402                 continue;
    403             }
    404 
    405             static_bit_val = soc_mem_field32_get(unit, l2x_data[unit].l2mem,
    406                                                  entry, STATIC_BITf);
    407             if (stl2 || (stl2 == static_bit_val)) {
    408                 soc_l2x_sync_delete(unit, entry, index, flags);
    409             }
    410         }
    411         goto exit;
    412     }
    413 
    414     if (search_key == SOC_L2X_VLAN_DEL) {
    415         for (index = 0; index < max_index; index++,
    416             entry += l2x_data[unit].entry_words) {
    417             if (!L2X_IS_VALID_ENTRY(unit, l2x_data[unit].l2mem, 
    418                                     entry, valid_bit)) {
    419                 continue;
    420             }
    421             vlan_id = soc_mem_field32_get(unit, l2x_data[unit].l2mem,
    422                                           entry, VLAN_IDf);
    423             if (vid != vlan_id) {
    424                 continue;
    425             }
    426 
    427             static_bit_val = soc_mem_field32_get(unit, l2x_data[unit].l2mem,
    428                                                  entry, STATIC_BITf);
    429             if (stl2 || (stl2 == static_bit_val)) {
    430                 soc_l2x_sync_delete(unit, entry, index, flags);
    431             }
    432         }
    433         goto exit;
    434     }
    435 
    436     if (search_key == SOC_L2X_VFI_DEL) {
    437 #ifdef BCM_TRIUMPH_SUPPORT
    438         int vfi_id;
    439         for (index = 0; index < max_index; index++,
    440             entry += l2x_data[unit].entry_words) {
    441             if (!L2X_IS_VALID_ENTRY(unit, l2x_data[unit].l2mem,
    442                                     entry, valid_bit)) {
    443                 continue;
    444             }
    445             vfi_id = soc_mem_field32_get(unit, l2x_data[unit].l2mem,
    446                                          entry, VFIf);
    447             if (vfi != vfi_id) {
    448                 continue;
    449             }
    450 
    451             static_bit_val = soc_mem_field32_get(unit, l2x_data[unit].l2mem,
    452                                                  entry, STATIC_BITf);
    453             if (stl2 || (stl2 == static_bit_val)) {
    454                 soc_l2x_sync_delete(unit, entry, index, flags);
    455             }
    456         }
    457 #endif
    458         goto exit;
    459     }
    460 
    461     if (search_key == SOC_L2X_PORTMOD_VLAN_DEL) {
    462         for (index = 0; index < max_index; index++,
    463             entry += l2x_data[unit].entry_words) {
    464             if (!L2X_IS_VALID_ENTRY(unit, l2x_data[unit].l2mem, 
    465                                     entry, valid_bit)) {
    466                 continue;
    467             }
    468             if (soc_feature(unit, soc_feature_trunk_group_overlay)) {
    469                 if (soc_mem_field32_get(unit, l2x_data[unit].l2mem, entry,
    470                                         Tf)) {
    471                     continue;
    472                 }
    473                 port_val = soc_mem_field32_get(unit, l2x_data[unit].l2mem,
    474                                                entry, PORT_NUMf);
    475             } else {
    476                 port_val = soc_mem_field32_get(unit, l2x_data[unit].l2mem,
    477                                                entry, TGID_PORTf);
    478             }
    479             mod_id = soc_mem_field32_get(unit, l2x_data[unit].l2mem,
    480                                          entry, MODULE_IDf);
    481             vlan_id = soc_mem_field32_get(unit, l2x_data[unit].l2mem,
    482                                           entry, VLAN_IDf);
    483             if ((vid != vlan_id) ||(port != port_val) ||(mod != mod_id)) {
    484                 continue;
    485             }
    486 
    487             static_bit_val = soc_mem_field32_get(unit, l2x_data[unit].l2mem,
    488                                                  entry, STATIC_BITf);
    489             if (stl2 || (stl2 == static_bit_val)) {
    490                 soc_l2x_sync_delete(unit, entry, index, flags);
    491             }
    492         }
    493         goto exit;
    494     }
    495 
    496     if ((search_key == SOC_L2X_TRUNK_DEL) || 
    497         (search_key == SOC_L2X_TRUNK_VLAN_DEL)) {
    498         trunk128 = soc_feature(unit, soc_feature_trunk_extended);
    499 
    500         if (trunk128) {
    501             if (!soc_feature(unit, soc_feature_trunk_group_overlay)) {
    502                 tgid_hi = (tid & SOC_L2X_TGID_PORT_TRUNK_MASK_HI) >>
    503                           SOC_TRUNK_BIT_POS(unit);
    504                 tgid_lo = tid & SOC_L2X_TGID_PORT_TRUNK_MASK;
    505                 tgid_lo |= SOC_L2X_TGID_TRUNK_INDICATOR(unit);
    506             }
    507 
    508             for (index = 0; index < max_index; index++,
    509                 entry += l2x_data[unit].entry_words) {
    510                 if (!L2X_IS_VALID_ENTRY(unit, l2x_data[unit].l2mem, 
    511                                         entry, valid_bit)) {
    512                     continue;
    513                 }
    514                 if (soc_feature(unit, soc_feature_trunk_group_overlay)) {
    515                     if (!soc_mem_field32_get(unit, l2x_data[unit].l2mem,
    516                                               entry, Tf) ||
    517                         soc_mem_field32_get(unit, l2x_data[unit].l2mem,
    518                                              entry, TGIDf) != tid) {
    519                         continue;
    520                     }
    521                     if ((search_key == SOC_L2X_TRUNK_VLAN_DEL) && 
    522                         (vid != soc_mem_field32_get(unit, l2x_data[unit].l2mem,
    523                                                     entry, VLAN_IDf))) {
    524                         continue;
    525 
    526                     }
    527                 } else {
    528                     port_val = soc_mem_field32_get(unit, l2x_data[unit].l2mem,
    529                                                     entry, TGID_PORTf);
    530                     tgid_val = soc_mem_field32_get(unit, l2x_data[unit].l2mem,
    531                                                     entry, MODULE_IDf);
    532 
    533                     if ((tgid_lo != port_val) ||(tgid_hi != tgid_val)) {
    534                         continue;
    535                     }
    536                     if ((search_key == SOC_L2X_TRUNK_VLAN_DEL) && 
    537                         (vid != soc_mem_field32_get(unit, l2x_data[unit].l2mem,
    538                                                     entry, VLAN_IDf))) {
    539                         continue;
    540 
    541                     }
    542                 }
    543 
    544                 static_bit_val = soc_mem_field32_get(unit, l2x_data[unit].l2mem,
    545                                                      entry, STATIC_BITf);
    546                 if (stl2 || (stl2 == static_bit_val)) {
    547                     soc_l2x_sync_delete(unit, entry, index, flags);
    548                 }
    549             }
    550         } else {
    551             tid &= SOC_L2X_TGID_PORT_TRUNK_MASK;
    552             tid |= SOC_L2X_TGID_TRUNK_INDICATOR(unit);
    553 
    554             for (index = 0; index < max_index; index++,
    555                 entry += l2x_data[unit].entry_words) {
    556                 if (!L2X_IS_VALID_ENTRY(unit, l2x_data[unit].l2mem, 
    557                                         entry, valid_bit)) {
    558                     continue;
    559                 }
    560                 port_val = soc_mem_field32_get(unit, l2x_data[unit].l2mem,
    561                                                entry, TGID_PORTf);
    562                 if (tid != port_val ) {
    563                     continue;
    564                 }
    565                 if ((search_key == SOC_L2X_TRUNK_VLAN_DEL) && 
    566                     (vid != soc_mem_field32_get(unit, l2x_data[unit].l2mem,
    567                                                 entry, VLAN_IDf))) {
    568                     continue;
    569 
    570                 }
    571                 static_bit_val = soc_mem_field32_get(unit, l2x_data[unit].l2mem,
    572                                                      entry, STATIC_BITf);
    573                 if (stl2 || (stl2 == static_bit_val)) {
    574                     soc_l2x_sync_delete(unit, entry, index, flags);
    575                 }
    576             }
    577         }
    578         goto exit;
    579     }
    580 
    581     rv = SOC_E_PARAM;
    582 
    583 exit:
    584     (void)sal_sem_give(soc->l2x_lock);
    585     return rv;
    586 }
    587 
    588 /*
    589  * Function:
    590  * 	soc_l2x_sync_delete
    591  * Purpose:
    592  *	sync the SW shadow copy for the deleted entry from HW.
    593  * Parameters:
    594  *	unit - unit number.
    595  *	del_entry - entry deleted from the HW l2X memory
    596  * Returns:
    597  *      SOC_E_XX
    598  */
    599 
    600 int
    601 soc_l2x_sync_delete(int unit, uint32 *del_entry, int index, uint32 flags)
    602 {
    603     soc_control_t   *soc = SOC_CONTROL(unit);
    604     int                 max_index;
    605     uint32              *tab_p;
    606 
    607     LOG_VERBOSE(BSL_LS_SOC_ARL,
    608                 (BSL_META_U(unit,
    609                             "soc_l2x_sync_delete: unit=%d index=%d\n"),
    610                  unit, index));
    611 
    612     if (soc->l2x_pid == SAL_THREAD_ERROR) {
    613         /* thread not running */
    614         return SOC_E_NONE;
    615     }
    616 
    617     if (l2x_data[unit].l2mem == INVALIDm) {
    618         return SOC_E_NONE;
    619     }
    620 
    621     max_index = soc_mem_index_max(unit, l2x_data[unit].l2mem);
    622     if (index > max_index) {
    623 #ifdef BCM_HURRICANE3_SUPPORT
    624         if ((SOC_IS_HURRICANE3(unit) || SOC_IS_GREYHOUND2(unit)) && 
    625             (index & SOC_L2X_GEN_RESP_INDEX_L2_OVERFLOW(unit))) {
    626             /* Entry learnt in L2_ENTRY_OVERFLOW */
    627             return SOC_E_NONE;
    628         }
    629 #endif /* BCM_HURRICANE3_SUPPORT */         
    630         return SOC_E_PARAM;
    631     }
    632     if (l2x_data[unit].shadow_tab == NULL) {
    633         LOG_WARN(BSL_LS_SOC_ARL,
    634                     (BSL_META_U(unit,
    635                                 "soc_l2x_sync_delete: l2x_data[%d].shadow_tab is NULL!!!\n"),
    636                      unit));
    637         return SOC_E_NONE;
    638     }
    639     /*
    640      * validate that the entry in the shadow copy is same as the entry
    641      * deleted.
    642      */
    643     tab_p = l2x_data[unit].shadow_tab + (index * l2x_data[unit].entry_words);
    644     if (L2X_ENTRY_EQL(unit, tab_p, del_entry,
    645                 WORDS2BYTES(l2x_data[unit].entry_words), 0)) {
    646         L2X_ENTRY_DELETED_SET(unit, index);
    647         /* Bitmap that indicates to suppress callback */
    648         if ((flags & SOC_L2X_NO_CALLBACKS)) {
    649             L2X_ENTRY_CALLBACK_SET(unit, index);
    650         }
    651     }
    652 
    653     return SOC_E_NONE;
    654 }
    655 
    656 /*
    657  * Function:
    658  * 	soc_l2x_sync_delete_by_port
    659  * Purpose:
    660  *	sync the SW shadow copy for the deleted entryies based on port.
    661  * Parameters:
    662  *	unit - unit number.
    663  *	port - port number.
    664  * Returns:
    665  *      SOC_E_XX
    666  */
    667 
    668 int
    669 soc_l2x_sync_delete_by_port(int unit, int mod, soc_port_t port,
    670                             uint32 flags)
    671 {
    672     return _soc_l2x_sync_delete_by(unit, mod, port, 0, 0, 0,
    673                                    flags, SOC_L2X_PORTMOD_DEL);
    674 }
    675 
    676 /*
    677  * Function:
    678  * 	soc_l2x_sync_delete_by_trunk
    679  * Purpose:
    680  *	sync the SW shadow copy for the deleted entryies based on trunk id.
    681  * Parameters:
    682  *	unit - unit number.
    683  *	port - port number.
    684  * Returns:
    685  *      SOC_E_XX
    686  */
    687 
    688 int
    689 soc_l2x_sync_delete_by_trunk(int unit, int tid, uint32 flags)
    690 {
    691     return _soc_l2x_sync_delete_by(unit, 0, 0, 0, tid, 0,
    692                                    flags, SOC_L2X_TRUNK_DEL);
    693 }
    694 
    695 /*
    696  * Function:
    697  * 	soc_l2x_start
    698  * Purpose:
    699  *   	Initialize shadow table and start L2X thread to maintain it
    700  * Parameters:
    701  *	unit - unit number.
    702  *	flags - SOC_L2X_FLAG_xxx
    703  *	interval - time between resynchronization passes
    704  * Returns:
    705  *	SOC_E_MEMORY if can't create thread.
    706  */
    707 
    708 int
    709 soc_l2x_start(int unit, uint32 flags, sal_usecs_t interval)
    710 {
    711     soc_control_t   *soc = SOC_CONTROL(unit);
    712     int         pri;
    713 #ifdef BCM_XGS3_SWITCH_SUPPORT
    714     int                 mode;
    715 #endif
    716 #ifdef BCM_TRIUMPH3_SUPPORT
    717     if SOC_IS_TRIUMPH3(unit) {
    718         return soc_tr3_l2x_start(unit, flags, interval);
    719     }
    720 #endif
    721     LOG_INFO(BSL_LS_SOC_ARL,
    722              (BSL_META_U(unit,
    723                          "soc_l2x_start: unit=%d flags=0x%x interval=%d\n"),
    724               unit, flags, interval));
    725 
    726     if (!soc_feature(unit, soc_feature_arl_hashed)) {
    727         return SOC_E_UNAVAIL;
    728     }
    729 
    730     if (soc->l2x_interval != 0) {
    731         SOC_IF_ERROR_RETURN(soc_l2x_stop(unit));
    732     }
    733 
    734     sal_snprintf(soc->l2x_name, sizeof (soc->l2x_name),
    735                  "bcmL2X.%d", unit);
    736 
    737     if (soc->l2x_pid == SAL_THREAD_ERROR) {
    738         pri = soc_property_get(unit, spn_L2XMSG_THREAD_PRI, 50);
    739 #ifdef BCM_XGS3_SWITCH_SUPPORT
    740         mode = soc_l2x_mode_cfg_get(unit);
    741 
    742         if (soc_feature(unit, soc_feature_l2_modfifo) && (mode == L2MODE_FIFO)) {
    743 
    744             SOC_CONTROL_LOCK(unit);
    745             soc->l2x_mode = mode;
    746             soc->l2x_flags = flags;
    747             soc->l2x_interval = interval;
    748 
    749             if (interval == 0) {
    750                 SOC_CONTROL_UNLOCK(unit);
    751                 return SOC_E_NONE;
    752             }
    753 #ifdef BCM_CMICX_SUPPORT
    754             if (SOC_IS_TRIDENT3X(unit)) {
    755                 _soc_cmicx_l2mod_start(unit, flags, interval);
    756             } else
    757 #endif
    758 #ifdef BCM_CMICM_SUPPORT
    759             if (SOC_IS_TD2_TT2(unit) || SOC_IS_KATANA2(unit) || 
    760                 soc_feature(unit, soc_feature_fifo_dma_hu2)) {
    761                 _soc_l2mod_start(unit, flags, interval);
    762             } else 
    763 #endif
    764             {
    765                 soc_l2mod_start(unit, flags, interval);
    766             }
    767             SOC_CONTROL_UNLOCK(unit);
    768             l2x_data[unit].l2mem = INVALIDm;
    769         } else
    770 #endif
    771         {
    772             if (soc->l2x_external) {
    773                 /* Not supported for external L2 memory configuration. */
    774                 return SOC_E_NONE;
    775             }
    776 
    777             SOC_CONTROL_LOCK(unit);
    778             soc->l2x_mode = L2MODE_POLL;
    779             soc->l2x_flags = flags;
    780             soc->l2x_interval = interval;
    781 
    782             if (interval == 0) {
    783                 SOC_CONTROL_UNLOCK(unit);
    784                 return SOC_E_NONE;
    785             }
    786             soc->l2x_pid = sal_thread_create(soc->l2x_name,
    787                                              SAL_THREAD_STKSZ,
    788                                              pri,
    789                                              _soc_l2x_thread,
    790                                              INT_TO_PTR(unit));
    791             if (soc->l2x_pid == SAL_THREAD_ERROR) {
    792                 LOG_ERROR(BSL_LS_SOC_L2,
    793                           (BSL_META_U(unit,
    794                                       "soc_l2x_start: Could not start L2X thread\n")));
    795                 SOC_CONTROL_UNLOCK(unit);
    796                 return SOC_E_MEMORY;
    797             }
    798             SOC_CONTROL_UNLOCK(unit);
    799         }
    800     }
    801 
    802     return SOC_E_NONE;
    803 }
    804 
    805 /*
    806  * Function:
    807  * 	soc_l2x_stop
    808  * Purpose:
    809  *   	Stop L2X-related thread
    810  * Parameters:
    811  *	unit - unit number.
    812  * Returns:
    813  *	SOC_E_XXX
    814  */
    815 
    816 int
    817 soc_l2x_stop(int unit)
    818 {
    819     soc_control_t   *soc = SOC_CONTROL(unit);
    820     int         rv = SOC_E_NONE;
    821     soc_timeout_t   to;
    822 #ifdef BCM_XGS3_SWITCH_SUPPORT
    823     int                 mode;
    824 #endif
    825 #ifdef BCM_TRIUMPH3_SUPPORT
    826     if SOC_IS_TRIUMPH3(unit) {
    827         return soc_tr3_l2x_stop(unit);
    828     }
    829 #endif
    830     LOG_INFO(BSL_LS_SOC_ARL,
    831              (BSL_META_U(unit,
    832                          "soc_l2x_stop: unit=%d\n"), unit));
    833 
    834     SOC_CONTROL_LOCK(unit);
    835     soc->l2x_interval = 0;  /* Request exit */
    836     SOC_CONTROL_UNLOCK(unit);
    837 
    838     if (soc->l2x_pid != SAL_THREAD_ERROR) {
    839         /* Wake up thread so it will check the exit flag */
    840 #ifdef BCM_XGS3_SWITCH_SUPPORT
    841         mode = soc_l2x_mode_cfg_get(unit);
    842         if (soc_feature(unit, soc_feature_l2_modfifo) &&
    843             (mode == L2MODE_FIFO)) {
    844 #ifdef BCM_CMICX_SUPPORT
    845             if (SOC_IS_TRIDENT3X(unit)) {
    846                 _soc_cmicx_l2mod_stop(unit);
    847             } else
    848 #endif
    849 #ifdef BCM_CMICM_SUPPORT
    850             if (SOC_IS_TD2_TT2(unit) || SOC_IS_KATANA2(unit) ||
    851                 soc_feature(unit, soc_feature_fifo_dma_hu2)) {
    852                 _soc_l2mod_stop(unit);
    853             } else 
    854 #endif
    855             {
    856                 soc_l2mod_stop(unit);
    857             }
    858         } else
    859 #endif
    860         {
    861             if (NULL != soc->l2x_notify) {
    862                 sal_sem_give(soc->l2x_notify);
    863             }
    864         }
    865 
    866         /* Give thread a few seconds to wake up and exit */
    867         if (SAL_BOOT_SIMULATION) {
    868             soc_timeout_init(&to, 30 * 1000000, 0);
    869         } else {
    870             soc_timeout_init(&to, 10 * 1000000, 0);
    871         }
    872 
    873         while (soc->l2x_pid != SAL_THREAD_ERROR) {
    874             if (soc_timeout_check(&to)) {
    875                 LOG_ERROR(BSL_LS_SOC_L2,
    876                           (BSL_META_U(unit,
    877                                       "soc_l2x_stop: thread will not exit\n")));
    878                 rv = SOC_E_INTERNAL;
    879                 break;
    880             }
    881         }
    882     }
    883 
    884     return rv;
    885 }
    886 
    887 #if defined(BCM_TRIDENT2_SUPPORT)
    888 STATIC int
    889 _soc_trident2_l2x_sync_multi_buckets(int unit, uint32 *new_entry, 
    890                                      uint8 shadow_hit_bits, int *mac_moved)
    891 {
    892     int num_banks = 0;
    893     int bank_idx = 0;
    894     int hw_bank = 0;
    895     int bucket_base = 0;
    896     int entry_idx = 0;
    897     int delete_marked, callback_suppress;
    898     uint32 *shadow_entry = NULL;
    899     uint32 bucket;
    900     soc_control_t *soc = SOC_CONTROL(unit);
    901     soc_mem_t l2mem = l2x_data[unit].l2mem;
    902     int entry_words = l2x_data[unit].entry_words;
    903     SHR_BITDCL *delete_map = l2x_data[unit].delete_map;
    904     SHR_BITDCL *callback_map = l2x_data[unit].callback_map;
    905     soc_field_t l2x_vld = VALIDf;
    906     int bucket_size = 4; /* 4 entries per bucket */
    907 
    908     if (soc_feature(unit, soc_feature_base_valid)) {
    909         l2x_vld = BASE_VALIDf;
    910     }
    911 
    912     SOC_IF_ERROR_RETURN(
    913         soc_trident2_hash_bank_count_get(unit, l2mem, &num_banks));
    914     for (bank_idx = 0; bank_idx < num_banks; bank_idx++) {
    915 #ifdef BCM_APACHE_SUPPORT
    916         if (SOC_IS_APACHE(unit)) {
    917             SOC_IF_ERROR_RETURN
    918                 (soc_apache_hash_bank_number_get(unit, l2mem, bank_idx,
    919                                                    &hw_bank));
    920             SOC_IF_ERROR_RETURN
    921                 (soc_ap_hash_bucket_get(unit, l2mem, hw_bank, new_entry,
    922                                         &bucket));
    923             bucket_base = soc_ap_hash_index_get(unit, l2mem, hw_bank, bucket);
    924         } else
    925 #endif /* BCM_APACHE_SUPPORT */
    926 #ifdef BCM_TOMAHAWK_SUPPORT
    927         if (SOC_IS_TOMAHAWKX(unit)) {
    928 #if defined(BCM_TOMAHAWK3_SUPPORT)
    929             if (SOC_IS_TOMAHAWK3(unit)) {
    930                 SOC_IF_ERROR_RETURN
    931                     (soc_tomahawk3_hash_bank_number_get(unit, l2mem, bank_idx,
    932                                                         &hw_bank));
    933                 SOC_IF_ERROR_RETURN
    934                     (soc_tomahawk3_hash_bucket_get(unit, l2mem, hw_bank,
    935                                                    new_entry, &bucket));
    936                 bucket_base = soc_tomahawk3_hash_index_get(unit, l2mem, hw_bank,
    937                                                            bucket);
    938             } else
    939 #endif /* BCM_TOMAHAWK3_SUPPORT */
    940             {
    941                 SOC_IF_ERROR_RETURN
    942                     (soc_tomahawk_hash_bank_number_get(unit, l2mem, bank_idx,
    943                                                        &hw_bank));
    944                 SOC_IF_ERROR_RETURN
    945                     (soc_th_hash_bucket_get(unit, l2mem, hw_bank, new_entry,
    946                                             &bucket));
    947                 bucket_base = soc_th_hash_index_get(unit, l2mem, hw_bank,
    948                                                     bucket);
    949             }
    950         } else
    951 #endif /* BCM_TOMAHAWK_SUPPORT */
    952         {
    953             SOC_IF_ERROR_RETURN
    954                 (soc_trident2_hash_bank_number_get(unit, l2mem, bank_idx,
    955                                                    &hw_bank));
    956             SOC_IF_ERROR_RETURN
    957                 (soc_hash_bucket_get(unit, l2mem, hw_bank, new_entry,
    958                                      &bucket));
    959             bucket_base = soc_hash_index_get(unit, l2mem, hw_bank, bucket);
    960         }
    961         shadow_entry = l2x_data[unit].shadow_tab + (bucket_base * entry_words);
    962         for (entry_idx = 0; entry_idx < bucket_size; entry_idx++) {
    963             if (soc_mem_field32_get(unit, l2mem, shadow_entry, l2x_vld) &&
    964                 soc_mem_compare_key(unit, l2mem, new_entry, shadow_entry) == 0) {
    965                 break;
    966             }
    967             shadow_entry += entry_words;
    968         }
    969         if (entry_idx < bucket_size) {
    970             break;
    971         }
    972     }
    973 
    974     if (bank_idx < num_banks) {
    975         /* This MAC existed previously in the bucket of another bank.
    976          * Check if everything at the new location is the same (ignoring
    977          * hit bit).  If so, there is no delete or change processing.
    978          */
    979          if (!(shadow_hit_bits & L2X_SHADOW_HIT_BITS)) {
    980              if (!(shadow_hit_bits & L2X_SHADOW_HIT_DST)) {
    981                  soc_L2Xm_field32_set(unit, shadow_entry, HITDAf,
    982                                       soc_L2Xm_field32_get(unit, new_entry,
    983                                                            HITDAf));
    984              }
    985              if (!(shadow_hit_bits & L2X_SHADOW_HIT_SRC)) {
    986                  soc_L2Xm_field32_set(unit, shadow_entry, HITSAf,
    987                                       soc_L2Xm_field32_get(unit, new_entry,
    988                                                            HITSAf));
    989              }
    990          }
    991         /* Check if the entry has been deleted and is marked for
    992          * delete.
    993          */
    994         if (SOC_L2_DEL_SYNC_LOCK(soc) < 0) {
    995             return SOC_E_RESOURCE;
    996         }
    997         delete_marked = SHR_BITGET(delete_map, bucket_base + entry_idx);
    998         callback_suppress = SHR_BITGET(callback_map, bucket_base + entry_idx);
    999         SOC_L2_DEL_SYNC_UNLOCK(soc);
   1000         if (L2X_ENTRY_EQL(unit, shadow_entry, new_entry,
   1001                              WORDS2BYTES(l2x_data[unit].entry_words), 0)) {
   1002             if (delete_marked) {
   1003                 /* Entry got learnt again after delete */
   1004                 if (callback_suppress) {
   1005                     /* Indicate re-learn */
   1006                     soc_l2x_callback(unit, 0, NULL, (l2x_entry_t *)new_entry);
   1007                 } else {
   1008                     /* Indicate delete and re-learn */
   1009                     soc_l2x_callback(unit, 0, (l2x_entry_t *)shadow_entry, NULL);
   1010                     soc_l2x_callback(unit, 0, NULL, (l2x_entry_t *)new_entry);
   1011                 }
   1012             }
   1013             /* Invalid entry in shadow table */
   1014             soc_L2Xm_field32_set(unit, shadow_entry, l2x_vld, 0);
   1015             *mac_moved = TRUE;
   1016             return SOC_E_NONE;
   1017         }
   1018         /* Issue change (delete & insert) */
   1019         if (!callback_suppress) {
   1020             soc_l2x_callback(unit, 0, (l2x_entry_t *)shadow_entry,
   1021                              (l2x_entry_t *)new_entry);
   1022         }
   1023         /* Invalid entry in the shadow table */
   1024         soc_L2Xm_field32_set(unit, shadow_entry, l2x_vld, 0);
   1025         *mac_moved = TRUE;
   1026         return SOC_E_NONE;
   1027     }
   1028     *mac_moved = FALSE;
   1029     return SOC_E_NONE;
   1030 }
   1031 #endif
   1032 
   1033 /*
   1034  * Function:
   1035  *	_soc_l2x_sync_bucket
   1036  * Purpose:
   1037  *	Compare the old contents of a hash bucket (8 entries) to the
   1038  *	next contents, make any ARL callbacks that are necessary,
   1039  *	and sync that bucket in the shadow table.
   1040  * Parameters:
   1041  *	unit - StrataSwitch unit #
   1042  *	old_bucket - Previous bucket contents (SOC_L2X_BUCKET_SIZE entries)
   1043  *	new_bucket - New bucket contents (SOC_L2X_BUCKET_SIZE entries)
   1044  *	shadow_hit_bits - perform the notify callback even if
   1045  *			only hit bits change.
   1046  *	bucket_index - start index of bucket within chunk
   1047  *	p_chunk_del_map - pointer to chunk's delete map
   1048  * Notes:
   1049  *	It's necessary to process deletions first, then insertions.
   1050  *	If an entry moves within the hash bucket, or some field such
   1051  *	as PORT changes, the application first receives a callback
   1052  *	for a deletion, and then for an insertion.
   1053  */
   1054 
   1055 STATIC void
   1056 _soc_l2x_sync_bucket(int unit,
   1057                      uint32 *old_bucket,
   1058                      uint32 *new_bucket,
   1059                      uint8 shadow_hit_bits, int bucket_index,
   1060                      SHR_BITDCL *p_chunk_del_map, 
   1061                      SHR_BITDCL *p_chunk_cb_map,
   1062                      SHR_BITDCL *p_bucket_sr_map)
   1063 {
   1064     int         io, in, delete_marked, callback_suppress;
   1065     soc_field_t         valid_bit = VALIDf;
   1066     uint32              *old_p, *new_p;
   1067 #if defined(BCM_TRIDENT2_SUPPORT)
   1068     int rv = SOC_E_NONE;
   1069     int mac_moved = 0;
   1070 #endif
   1071 #if defined(BCM_TRIDENT2PLUS_SUPPORT) || defined(BCM_APACHE_SUPPORT)
   1072     int key_type = 0;
   1073     int remote_trunk = 0;
   1074     int trunk = 0;
   1075 #endif
   1076 #ifdef BCM_TSN_SUPPORT
   1077     int sr_ref_updated = 0;
   1078 #endif
   1079 
   1080     /*
   1081      * Process deletions, which will be any entry that was in the bucket
   1082      * before but whose key is no longer found anywhere in the bucket,
   1083      * and changes, which will be any entry whose key is still found but
   1084      * whose associated data (port, etc.) has changed.
   1085      */
   1086 
   1087     if (soc_feature(unit, soc_feature_base_valid)) {
   1088         valid_bit = BASE_VALIDf;
   1089     }
   1090 
   1091     old_p = old_bucket;
   1092     for (io = 0; io < SOC_L2X_BUCKET_SIZE; io++,
   1093         old_p += l2x_data[unit].entry_words) {
   1094 
   1095         /*
   1096          * No deletion or change is needed for invalid entries.
   1097          */
   1098         if (!soc_mem_field32_get(unit, l2x_data[unit].l2mem,
   1099                                  old_p, valid_bit)) {
   1100             continue;
   1101         }
   1102 
   1103         /*
   1104          * Check if the entry has been deleted and is marked for
   1105          * delete.
   1106          */
   1107         delete_marked = SHR_BITGET(p_chunk_del_map, bucket_index + io);
   1108         callback_suppress = SHR_BITGET(p_chunk_cb_map, bucket_index + io);
   1109 #ifdef BCM_TSN_SUPPORT
   1110         if (p_bucket_sr_map != NULL) {
   1111             sr_ref_updated = SHR_BITGET(p_bucket_sr_map, io);
   1112         }
   1113 #endif /* BCM_TSN_SUPPORT */
   1114         /*
   1115          * Quick check: if the entry is identical, it does not need any
   1116          * deletion or change processing.  It may be valid or not.
   1117          */
   1118 
   1119         new_p = new_bucket + (io * l2x_data[unit].entry_words);
   1120         if (L2X_ENTRY_EQL(unit, old_p, new_p, 
   1121                     WORDS2BYTES(l2x_data[unit].entry_words), shadow_hit_bits)) {
   1122             if (delete_marked) {
   1123                 /* Entry got learnt again after delete */
   1124                 if (callback_suppress) {
   1125                     /* Indicate re-learn */
   1126                     soc_l2x_callback(unit, 0, NULL, (l2x_entry_t *) new_p);
   1127                 } else {
   1128                     /* Indicate delete and re-learn */
   1129                     soc_l2x_callback(unit, 0, (l2x_entry_t *) old_p, NULL);
   1130                     soc_l2x_callback(unit, 0, NULL, (l2x_entry_t *) new_p);
   1131                 }
   1132             }
   1133             continue;
   1134         }
   1135 
   1136         /*
   1137          * See if the old key still exists anywhere within the bucket.
   1138          */
   1139 
   1140         new_p = new_bucket;
   1141         for (in = 0; in < SOC_L2X_BUCKET_SIZE; in++) {
   1142             if (soc_mem_field32_get(unit, l2x_data[unit].l2mem,
   1143                                     new_p, valid_bit) &&
   1144                 soc_mem_compare_key(unit, l2x_data[unit].l2mem,
   1145                                     old_p, new_p) == 0) {
   1146                 break;
   1147             }
   1148             new_p += l2x_data[unit].entry_words;
   1149         }
   1150 
   1151         if (in == SOC_L2X_BUCKET_SIZE) {
   1152             /* It doesn't, so issue a delete. */
   1153             if (!callback_suppress) {
   1154 #if defined(BCM_TSN_SUPPORT)
   1155                 /* Decrease TSN/SR flowset reference count for L2 deletion */
   1156                 if (soc_feature(unit, soc_feature_tsn)) {
   1157                     if (!sr_ref_updated) {
   1158                         soc_l2x_callback(unit,
   1159                                          SOC_L2X_ENTRY_TSN_SR_FLOWSET_REF_CNT,
   1160                                          (l2x_entry_t *)old_p, NULL);
   1161                         if (p_bucket_sr_map != NULL) {
   1162                             SHR_BITCLR(p_bucket_sr_map, io);
   1163                         }
   1164                     }
   1165                 }
   1166 #endif /* BCM_TSN_SUPPORT */
   1167 #ifdef BCM_XGS_SWITCH_SUPPORT
   1168 #if defined(BCM_TOMAHAWK3_SUPPORT)
   1169                 if (SOC_IS_TOMAHAWK3(unit)) {
   1170                     int rv1 = SOC_E_NONE;
   1171                     int idx = -1;
   1172 
   1173                     /* Entry not found in this bucket. Search in L2 table to see
   1174                      * if it was shuffled. It it was shuffled, the same entry
   1175                      * will be present at some other location. If the search
   1176                      * did not find it, it means the entry was deleted, so  we
   1177                      * can issue a 'delete' callback. This code is required
   1178                      * because TH3 does not have mod fifo; in legacy devices,
   1179                      * mod fifo is configured to supress callbacks due to
   1180                      * internal (within SDK) shuffling of L2 entries
   1181                      */
   1182                     rv1 = soc_mem_generic_lookup(unit, L2Xm, MEM_BLOCK_ANY, 0,
   1183                                                  old_p, NULL, &idx);
   1184                     if (rv1 == SOC_E_NOT_FOUND) {
   1185                         soc_l2x_callback(unit, 0, (l2x_entry_t *) old_p, NULL);
   1186                     }
   1187 
   1188                 } else
   1189 #endif /* BCM_TOMAHAWK3_SUPPORT */
   1190 #endif /* BCM_XGS_SWITCH_SUPPORT */
   1191                 {
   1192                     soc_l2x_callback(unit, 0, (l2x_entry_t *) old_p, NULL);
   1193                 }
   1194             }
   1195             continue;
   1196         }
   1197 
   1198         /*
   1199          * Check if everything at the new location is the same (ignoring
   1200          * hit bit).  If so, there is no delete or change processing.
   1201          */
   1202 
   1203         if (!(shadow_hit_bits & L2X_SHADOW_HIT_BITS)) {
   1204             if (!(shadow_hit_bits & L2X_SHADOW_HIT_DST)) { 
   1205                 soc_L2Xm_field32_set(unit, old_p, HITDAf,
   1206                                      soc_L2Xm_field32_get(unit, new_p,
   1207                                                           HITDAf));
   1208             }
   1209             if (!(shadow_hit_bits & L2X_SHADOW_HIT_SRC)) {
   1210                 soc_L2Xm_field32_set(unit, old_p, HITSAf,
   1211                                      soc_L2Xm_field32_get(unit, new_p,
   1212                                                           HITSAf));
   1213             }
   1214         }
   1215 
   1216         if (L2X_ENTRY_EQL(unit, old_p, new_p, 
   1217                  WORDS2BYTES(l2x_data[unit].entry_words), shadow_hit_bits)) {
   1218 #if defined(BCM_TRIDENT2PLUS_SUPPORT) || defined(BCM_APACHE_SUPPORT)
   1219             if (soc_feature(unit, soc_feature_no_l2_remote_trunk)) {
   1220                 key_type = soc_L2Xm_field32_get(unit, new_p, KEY_TYPEf);
   1221                 trunk = soc_L2Xm_field32_get(unit, new_p, Tf);
   1222                 remote_trunk = soc_L2Xm_field32_get(unit, new_p, REMOTE_TRUNKf);
   1223 
   1224                 if (remote_trunk && trunk && (key_type == 0)) {
   1225                     /* Clear REMOTE_TRUNK in S/W new chunk */
   1226                     soc_L2Xm_field32_set(unit, new_p, REMOTE_TRUNKf, 0);
   1227 
   1228                     /* Clear REMOTE_TRUNK in H/W table */
   1229                     soc_mem_generic_insert(unit, L2Xm, MEM_BLOCK_ANY,
   1230                                            0, new_p, NULL, NULL);
   1231                     remote_trunk = 0;
   1232                     trunk = 0;
   1233                 }
   1234             }
   1235 #endif
   1236             if (delete_marked) {
   1237                 /* Entry got learnt again after delete */
   1238                 if (callback_suppress) {
   1239                     /* Indicate re-learn */
   1240                     soc_l2x_callback(unit, 0, NULL, (l2x_entry_t *) new_p);
   1241                 } else {
   1242                     /* Indicate delete and re-learn */
   1243                     soc_l2x_callback(unit, 0, (l2x_entry_t *) old_p, NULL);
   1244                     soc_l2x_callback(unit, 0, NULL, (l2x_entry_t *) new_p);
   1245                 }
   1246             }
   1247             continue;
   1248         }
   1249 
   1250 #if defined(BCM_TRIDENT2PLUS_SUPPORT) || defined(BCM_APACHE_SUPPORT)
   1251         if (soc_feature(unit, soc_feature_no_l2_remote_trunk)) {
   1252             key_type = soc_L2Xm_field32_get(unit, new_p, KEY_TYPEf);
   1253             trunk = soc_L2Xm_field32_get(unit, new_p, Tf);
   1254             remote_trunk = soc_L2Xm_field32_get(unit, new_p, REMOTE_TRUNKf);
   1255 
   1256             if (remote_trunk && trunk && (key_type == 0)) {
   1257                 /* Clear REMOTE_TRUNK in S/W new chunk */
   1258                 soc_L2Xm_field32_set(unit, new_p, REMOTE_TRUNKf, 0);
   1259 
   1260                 /* Clear REMOTE_TRUNK in H/W table */
   1261                 soc_mem_generic_insert(unit, L2Xm, MEM_BLOCK_ANY,
   1262                                        0, new_p, NULL, NULL);
   1263                 remote_trunk = 0;
   1264                 trunk = 0;
   1265             }
   1266         }
   1267 #endif
   1268         if (delete_marked) {
   1269             /* Entry got learnt again at another port after delete */
   1270             if (callback_suppress) {
   1271                 /* Indicate re-learn */
   1272                 soc_l2x_callback(unit, 0, NULL, (l2x_entry_t *) new_p);
   1273             } else {
   1274                 /* Indicate delete and re-learn */
   1275                 soc_l2x_callback(unit, 0, (l2x_entry_t *) old_p, NULL);
   1276                 soc_l2x_callback(unit, 0, NULL, (l2x_entry_t *) new_p);
   1277             }
   1278         } else {
   1279             /* Issue change (delete & insert) */
   1280             if (!callback_suppress) {
   1281 #if defined(BCM_TSN_SUPPORT)
   1282                 /* Update TSN/SR flowset reference count for L2 changes */
   1283                 if (soc_feature(unit, soc_feature_tsn)) {
   1284                     if (!sr_ref_updated) {
   1285                         soc_l2x_callback(unit,
   1286                                          SOC_L2X_ENTRY_TSN_SR_FLOWSET_REF_CNT,
   1287                                          (l2x_entry_t *)old_p,
   1288                                          (l2x_entry_t *)new_p);
   1289                         if (p_bucket_sr_map != NULL) {
   1290                             SHR_BITCLR(p_bucket_sr_map, io);
   1291                         }
   1292                     }
   1293                 }
   1294 #endif /* BCM_TSN_SUPPORT */
   1295                 soc_l2x_callback(unit, 0, (l2x_entry_t *) old_p,
   1296                                  (l2x_entry_t *) new_p);
   1297             }
   1298         }
   1299     }
   1300 
   1301     /*
   1302      * Process insertions, which will be any entry whose key was not in
   1303      * the bucket before, but is now.
   1304      */
   1305 
   1306     new_p = new_bucket;
   1307     for (in = 0; in < SOC_L2X_BUCKET_SIZE; in++,
   1308         new_p += l2x_data[unit].entry_words) {
   1309 
   1310 #ifdef BCM_TSN_SUPPORT
   1311         if (p_bucket_sr_map != NULL) {
   1312             sr_ref_updated = SHR_BITGET(p_bucket_sr_map, in);
   1313         }
   1314 #endif
   1315         /*
   1316          * Quick check: if the entry is identical, it does not need any
   1317          * insertion processing.  It may be valid or not.
   1318          */
   1319         old_p = old_bucket + (in * l2x_data[unit].entry_words);
   1320         if (L2X_ENTRY_EQL(unit, old_p, new_p,
   1321                  WORDS2BYTES(l2x_data[unit].entry_words), 0)) {
   1322             continue;
   1323         }
   1324 
   1325         /*
   1326          * No insert needed for invalid entries.
   1327          */
   1328 
   1329         if (!soc_mem_field32_get(unit, l2x_data[unit].l2mem,
   1330                                  new_p, valid_bit)) {
   1331             continue;
   1332         }
   1333 
   1334         /*
   1335          * If the same key already existed elsewhere within the bucket,
   1336          * it has already been taken care of by the change processing above.
   1337          */
   1338 
   1339         old_p = old_bucket;
   1340         for (io = 0; io < SOC_L2X_BUCKET_SIZE; io++) {
   1341             if (soc_mem_field32_get(unit, l2x_data[unit].l2mem,
   1342                                     old_p, valid_bit) &&
   1343                 soc_mem_compare_key(unit, l2x_data[unit].l2mem,
   1344                                     new_p, old_p) == 0) {
   1345                 break;
   1346             }
   1347             old_p += l2x_data[unit].entry_words;
   1348         }
   1349 
   1350         if (io < SOC_L2X_BUCKET_SIZE) {
   1351             continue;
   1352         }
   1353 
   1354         if (soc_feature(unit, soc_feature_ppa_bypass)) {
   1355             if (SOC_CONTROL(unit)->l2x_ppa_bypass == FALSE &&
   1356                 soc_mem_field32_get(unit, L2Xm, new_p, KEY_TYPEf) !=
   1357                 TR_L2_HASH_KEY_TYPE_BRIDGE) {
   1358                 SOC_CONTROL(unit)->l2x_ppa_bypass = TRUE;
   1359             }
   1360         }
   1361 
   1362 #if defined(BCM_TRIDENT2_SUPPORT)
   1363         /* Check whether this entry in the new bucket existed in 
   1364          * other buckets in another banks previously.
   1365          */
   1366         if (SOC_IS_TD2_TT2(unit) &&
   1367         	  soc_feature(unit, soc_feature_shared_hash_mem)) {
   1368             rv = _soc_trident2_l2x_sync_multi_buckets(unit, new_p, 
   1369                                                       shadow_hit_bits, 
   1370                                                       &mac_moved);
   1371             if (SOC_SUCCESS(rv)) {
   1372                 if (mac_moved == TRUE) {
   1373                     continue;
   1374                 }
   1375             }
   1376         }
   1377 #endif
   1378 
   1379 #if defined(BCM_TRIDENT2PLUS_SUPPORT) || defined(BCM_APACHE_SUPPORT)
   1380         if (soc_feature(unit, soc_feature_no_l2_remote_trunk)) {
   1381             key_type = soc_L2Xm_field32_get(unit, new_p, KEY_TYPEf);
   1382             trunk = soc_L2Xm_field32_get(unit, new_p, Tf);
   1383             remote_trunk = soc_L2Xm_field32_get(unit, new_p, REMOTE_TRUNKf);
   1384 
   1385             if (remote_trunk && trunk && (key_type == 0)) {
   1386                 /* Clear REMOTE_TRUNK in S/W new chunk */
   1387                 soc_L2Xm_field32_set(unit, new_p, REMOTE_TRUNKf, 0);
   1388 
   1389                 /* Clear REMOTE_TRUNK in H/W table */
   1390                 soc_mem_generic_insert(unit, L2Xm, MEM_BLOCK_ANY,
   1391                                        0, new_p, NULL, NULL);
   1392                 remote_trunk = 0;
   1393                 trunk = 0;
   1394             }
   1395         }
   1396 #endif
   1397 #if defined(BCM_TSN_SUPPORT)
   1398         /* Increase TSN/SR flowset reference count for L2 insertions */
   1399         if (soc_feature(unit, soc_feature_tsn)) {
   1400             if (!sr_ref_updated) {
   1401                 soc_l2x_callback(unit,
   1402                                  SOC_L2X_ENTRY_TSN_SR_FLOWSET_REF_CNT,
   1403                                  NULL, (l2x_entry_t *)new_p);
   1404                 if (p_bucket_sr_map != NULL) {
   1405                     SHR_BITCLR(p_bucket_sr_map, in);
   1406                 }
   1407             }
   1408         }
   1409 #endif /* BCM_TSN_SUPPORT */
   1410         soc_l2x_callback(unit, 0, NULL, (l2x_entry_t *) new_p);
   1411     }
   1412 
   1413     /* Sync shadow copy */
   1414 
   1415     sal_memcpy(old_bucket, new_bucket,
   1416                SOC_L2X_BUCKET_SIZE * l2x_data[unit].entry_words * 4);
   1417 }
   1418 
   1419 /*
   1420  * Function:
   1421  * 	_soc_l2x_thread
   1422  * Purpose:
   1423  *   	Thread control for L2 shadow table maintenance
   1424  * Parameters:
   1425  *	unit_vp - StrataSwitch unit # (as a void *).
   1426  * Returns:
   1427  *	Nothing
   1428  * Notes:
   1429  *	Exits when l2x_rate is set to zero and semaphore is given.  The
   1430  *	table is processed one chunk at a time (spn_L2XMSG_CHUNKS chunks
   1431  *	total) in order to reduce memory requirements for the temporary
   1432  *	DMA buffer and to give the CPU a break from bursts of activity.
   1433  */
   1434 
   1435 STATIC void
   1436 _soc_l2x_thread(void *unit_vp)
   1437 {
   1438     int         unit = PTR_TO_INT(unit_vp);
   1439     soc_control_t   *soc = SOC_CONTROL(unit);
   1440     int         rv;
   1441     uint32      *shadow_tab = NULL, *chunk_buf = NULL;
   1442     SHR_BITDCL          *delete_map = NULL;
   1443     SHR_BITDCL          *chunk_delete_map = NULL;
   1444     SHR_BITDCL          *callback_map = NULL;
   1445     SHR_BITDCL          *chunk_callback_map = NULL;
   1446 #ifdef BCM_TSN_SUPPORT
   1447     SHR_BITDCL          *sr_ref_map = NULL;
   1448     SHR_BITDCL          *bucket_sr_ref_map = NULL;
   1449     int         is_tsn_or_sr = FALSE; /* TSN or SR support */
   1450 #endif
   1451     int         index_count;
   1452     int         chunk_count, chunk_size;
   1453     int         chunk_index, bucket_index;
   1454     uint32      *tab_p, *buf_p;
   1455     int         interval;
   1456     sal_usecs_t     stime, etime;
   1457 
   1458     l2x_data[unit].l2mem = L2Xm;
   1459     l2x_data[unit].entry_bytes = soc_mem_entry_bytes(unit, l2x_data[unit].l2mem);
   1460     l2x_data[unit].entry_words = soc_mem_entry_words(unit, l2x_data[unit].l2mem);
   1461 
   1462     assert(soc_mem_index_min(unit, l2x_data[unit].l2mem) == 0);
   1463     index_count = soc_mem_index_count(unit, l2x_data[unit].l2mem);
   1464     if (index_count <= 0) {
   1465         LOG_ERROR(BSL_LS_SOC_L2,
   1466                   (BSL_META_U(unit,
   1467                               "soc_l2x_thread: table size is 0 \n")));
   1468         soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
   1469                            SOC_SWITCH_EVENT_THREAD_L2X, __LINE__, SOC_E_EMPTY);
   1470         goto cleanup_exit;
   1471     }
   1472 
   1473     chunk_count = soc_property_get(unit, spn_L2XMSG_CHUNKS, 8);
   1474     chunk_size = index_count / chunk_count;
   1475 
   1476     assert(chunk_size > 0);
   1477     assert(chunk_size % SOC_L2X_BUCKET_SIZE == 0);
   1478 
   1479     shadow_tab = sal_alloc(index_count * l2x_data[unit].entry_words * 4,
   1480                            "l2x_old");
   1481 
   1482     chunk_buf = soc_cm_salloc(unit,
   1483                               chunk_size * l2x_data[unit].entry_words * 4,
   1484                               "l2x_new");
   1485 
   1486     delete_map = sal_alloc(SHR_BITALLOCSIZE(index_count), "l2x_delete_map");
   1487     callback_map = sal_alloc(SHR_BITALLOCSIZE(index_count), "l2x_callback_map");
   1488 
   1489     chunk_delete_map = 
   1490     sal_alloc(SHR_BITALLOCSIZE(chunk_size), "l2x_chunk_delete_map");
   1491     chunk_callback_map = 
   1492     sal_alloc(SHR_BITALLOCSIZE(chunk_size), "l2x_chunk_callback_map");
   1493 #ifdef BCM_TSN_SUPPORT
   1494     if (soc_feature(unit, soc_feature_tsn)) {
   1495         sr_ref_map =
   1496             sal_alloc(SHR_BITALLOCSIZE(index_count), "l2x_sr_ref_map");
   1497         bucket_sr_ref_map =
   1498             sal_alloc(SHR_BITALLOCSIZE(SOC_L2X_BUCKET_SIZE),
   1499                       "l2x_bucket_sr_ref_map");
   1500         is_tsn_or_sr = TRUE;
   1501     }
   1502 #endif
   1503 
   1504     if (shadow_tab == NULL || chunk_buf == NULL || 
   1505         delete_map == NULL || chunk_delete_map == NULL || 
   1506 #ifdef BCM_TSN_SUPPORT
   1507         ((is_tsn_or_sr) &&
   1508          (sr_ref_map == NULL || bucket_sr_ref_map == NULL)) ||
   1509 #endif
   1510         callback_map == NULL || chunk_callback_map == NULL) {
   1511         LOG_ERROR(BSL_LS_SOC_L2,
   1512                   (BSL_META_U(unit,
   1513                               "AbnormalThreadExit:soc_l2x_thread: not enough memory \n")));
   1514         soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
   1515                            SOC_SWITCH_EVENT_THREAD_L2X, __LINE__, SOC_E_MEMORY);
   1516         goto cleanup_exit;
   1517     }
   1518     
   1519 #ifdef BCM_HURRICANE3_SUPPORT
   1520     /* Prepare for sync L2 overflow table */
   1521     if ((soc_feature(unit, soc_feature_l2_overflow_bucket)) &&
   1522             (soc->l2_overflow_bucket_enable)) {
   1523         if (soc_hr3_l2_overflow_sync_init(unit) < 0) {
   1524             LOG_ERROR(BSL_LS_SOC_L2,
   1525                 (BSL_META_U(unit,
   1526                 "Error:soc_hr3_l2_overflow_sync_init: not enough memory \n")));
   1527             soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
   1528                            SOC_SWITCH_EVENT_THREAD_L2X, __LINE__, SOC_E_MEMORY);
   1529             goto cleanup_exit;
   1530         }
   1531     }
   1532 #endif /* BCM_HURRICANE3_SUPPORT */    
   1533     
   1534     /*
   1535      * Start with initially empty shadow table.
   1536      */
   1537 
   1538     sal_memset(shadow_tab, 0, index_count * l2x_data[unit].entry_words * 4);
   1539 
   1540     /*
   1541      * Clear the delete and callback map.
   1542      */
   1543     SHR_BITCLR_RANGE(delete_map, 0, index_count);
   1544     SHR_BITCLR_RANGE(callback_map, 0, index_count);
   1545 
   1546     l2x_data[unit].shadow_tab = shadow_tab;
   1547     l2x_data[unit].chunk_buf = chunk_buf;
   1548     l2x_data[unit].delete_map = delete_map;
   1549     l2x_data[unit].callback_map = callback_map;
   1550 #ifdef BCM_TSN_SUPPORT
   1551     if (is_tsn_or_sr) {
   1552         SHR_BITCLR_RANGE(sr_ref_map, 0, index_count);
   1553         l2x_data[unit].sr_ref_map = sr_ref_map;
   1554     }
   1555 #endif /* BCM_TSN_SUPPORT */
   1556     chunk_index = 0;
   1557     tab_p = shadow_tab;
   1558 
   1559     while ((interval = soc->l2x_interval) != 0) {
   1560         /*
   1561          * Read the next chunk of the L2 table using Table DMA.
   1562          */
   1563 
   1564         LOG_VERBOSE(BSL_LS_SOC_ARL,
   1565                     (BSL_META_U(unit,
   1566                                 "soc_l2x_thread: Process %d-%d\n"),
   1567                      chunk_index, chunk_index + chunk_size - 1));
   1568 
   1569         stime = sal_time_usecs();
   1570 
   1571         soc_mem_lock(unit, l2x_data[unit].l2mem);
   1572         if (SOC_L2_DEL_SYNC_LOCK(soc) < 0) {
   1573             LOG_ERROR(BSL_LS_SOC_L2,
   1574                       (BSL_META_U(unit,
   1575                                   "soc_l2x_thread: unable to take mutex\n")));
   1576             soc_mem_unlock(unit, l2x_data[unit].l2mem);
   1577             soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
   1578                                SOC_SWITCH_EVENT_THREAD_L2X, __LINE__,
   1579                                 SOC_E_RESOURCE);
   1580             goto cleanup_exit;
   1581         }
   1582 
   1583         if ((rv = soc_mem_read_range(unit, l2x_data[unit].l2mem,
   1584                                      MEM_BLOCK_ANY,chunk_index,
   1585                                      chunk_index + chunk_size - 1,
   1586                                      chunk_buf)) < 0) {
   1587             SOC_L2_DEL_SYNC_UNLOCK(soc);
   1588             soc_mem_unlock(unit, l2x_data[unit].l2mem);
   1589             LOG_ERROR(BSL_LS_SOC_L2,
   1590                       (BSL_META_U(unit,
   1591                                   "soc_l2x_thread: DMA failed: %s\n"),
   1592                                   soc_errmsg(rv)));
   1593 
   1594             soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
   1595                                SOC_SWITCH_EVENT_THREAD_L2X, __LINE__, rv);
   1596 
   1597             goto cleanup_exit;
   1598         } else {
   1599             SHR_BITCOPY_RANGE(chunk_delete_map, 0, delete_map, chunk_index, 
   1600                               chunk_size);
   1601             SHR_BITCOPY_RANGE(chunk_callback_map, 0, callback_map, chunk_index, 
   1602                               chunk_size);
   1603 
   1604             SHR_BITCLR_RANGE(delete_map, chunk_index, chunk_size);
   1605             SHR_BITCLR_RANGE(callback_map, chunk_index, chunk_size);
   1606 
   1607             SOC_L2_DEL_SYNC_UNLOCK(soc);
   1608             soc_mem_unlock(unit, l2x_data[unit].l2mem);
   1609 
   1610             /*
   1611              * Scan, compare, and sync the old and new chunks one bucket
   1612              * at a time.
   1613              */
   1614 
   1615             buf_p = chunk_buf;
   1616             for (bucket_index = 0; bucket_index < chunk_size; 
   1617                 bucket_index += SOC_L2X_BUCKET_SIZE) {
   1618 #ifdef BCM_TSN_SUPPORT
   1619                 if (is_tsn_or_sr) {
   1620                      soc_mem_lock(unit, l2x_data[unit].l2mem);
   1621                      SOC_L2_SR_LOCK(unit);
   1622                      SHR_BITCOPY_RANGE(bucket_sr_ref_map, 0, sr_ref_map,
   1623                                        chunk_index + bucket_index,
   1624                                        SOC_L2X_BUCKET_SIZE);
   1625 
   1626                      _soc_l2x_sync_bucket(unit, tab_p, buf_p,
   1627                                           soc->l2x_shadow_hit_bits,
   1628                                           bucket_index, chunk_delete_map,
   1629                                           chunk_callback_map,
   1630                                           bucket_sr_ref_map);
   1631                      SHR_BITCOPY_RANGE(sr_ref_map, chunk_index + bucket_index,
   1632                                        bucket_sr_ref_map,
   1633                                        0,
   1634                                        SOC_L2X_BUCKET_SIZE);
   1635                      SOC_L2_SR_UNLOCK(unit);
   1636                      soc_mem_unlock(unit, l2x_data[unit].l2mem);
   1637                 } else
   1638 #endif
   1639                 {
   1640                     _soc_l2x_sync_bucket(unit, tab_p, buf_p,
   1641                                          soc->l2x_shadow_hit_bits,
   1642                                          bucket_index, chunk_delete_map,
   1643                                          chunk_callback_map, NULL);
   1644                 }
   1645 
   1646                 tab_p += l2x_data[unit].entry_words * SOC_L2X_BUCKET_SIZE;
   1647                 buf_p += l2x_data[unit].entry_words * SOC_L2X_BUCKET_SIZE;
   1648             }
   1649 
   1650             if ((chunk_index += chunk_size) >= index_count) {
   1651                 chunk_index = 0;
   1652                 tab_p = shadow_tab;
   1653             }
   1654         }
   1655 
   1656         etime = sal_time_usecs();
   1657 
   1658         /*
   1659          * Implement the sleep using a semaphore timeout so if the task
   1660          * is requested to exit, it can do so immediately.
   1661          */
   1662 
   1663         LOG_VERBOSE(BSL_LS_SOC_ARL,
   1664                     (BSL_META_U(unit,
   1665                                 "soc_l2x_thread: unit=%d: done in %d usec\n"),
   1666                      unit,
   1667                      SAL_USECS_SUB(etime, stime)));
   1668 #if defined(BCM_HURRICANE3_SUPPORT)
   1669         /* Sync the L2 overflow table */
   1670         if ((chunk_index == 0) && 
   1671             (soc_feature(unit, soc_feature_l2_overflow_bucket)) &&
   1672             (soc->l2_overflow_bucket_enable)) {
   1673             soc_hr3_l2_overflow_sync(unit);
   1674             
   1675         }
   1676 
   1677 #endif /* BCM_HURRICANE3_SUPPORT */
   1678 
   1679         sal_sem_take(soc->l2x_notify, interval / chunk_count);
   1680     }
   1681 
   1682 cleanup_exit:
   1683 
   1684     (void)sal_sem_take(soc->l2x_lock, sal_sem_FOREVER);
   1685 
   1686     if (chunk_buf != NULL) {
   1687         soc_cm_sfree(unit, chunk_buf);
   1688         l2x_data[unit].chunk_buf = NULL;
   1689     }
   1690 
   1691     if (shadow_tab != NULL) {
   1692         sal_free(shadow_tab);
   1693         l2x_data[unit].shadow_tab = NULL;
   1694     }
   1695 
   1696     if (delete_map != NULL) {
   1697         sal_free(delete_map);
   1698         l2x_data[unit].delete_map = NULL;
   1699     }
   1700 
   1701     if (chunk_delete_map != NULL) {
   1702         sal_free(chunk_delete_map);
   1703     }
   1704 
   1705     if (callback_map != NULL) {
   1706         sal_free(callback_map);
   1707         l2x_data[unit].callback_map = NULL;
   1708     }
   1709 
   1710     if (chunk_callback_map != NULL) {
   1711         sal_free(chunk_callback_map);
   1712     }
   1713 
   1714 #ifdef BCM_TSN_SUPPORT
   1715     if (sr_ref_map != NULL) {
   1716         sal_free(sr_ref_map);
   1717         l2x_data[unit].sr_ref_map = NULL;
   1718     }
   1719     if (bucket_sr_ref_map != NULL) {
   1720         sal_free(bucket_sr_ref_map);
   1721     }
   1722 #endif
   1723 
   1724 #ifdef BCM_HURRICANE3_SUPPORT
   1725     /* Prepare for sync L2 overflow table */
   1726     if ((soc_feature(unit, soc_feature_l2_overflow_bucket)) &&
   1727             (soc->l2_overflow_bucket_enable)) {
   1728         soc_hr3_l2_overflow_sync_cleanup(unit);
   1729     }
   1730 #endif /* BCM_HURRICANE3_SUPPORT */    
   1731 
   1732     (void)sal_sem_give(soc->l2x_lock);
   1733 
   1734     LOG_INFO(BSL_LS_SOC_ARL,
   1735              (BSL_META_U(unit,
   1736                          "soc_l2x_thread: exiting\n")));
   1737 
   1738     soc->l2x_pid = SAL_THREAD_ERROR;
   1739     sal_thread_exit(0);
   1740 }
   1741 
   1742 #if defined(BCM_TSN_SUPPORT)
   1743 /*
   1744  * Function:
   1745  *    soc_l2x_sr_ref_sync
   1746  * Purpose:
   1747  *    Sync the SW shadow copy for SR flow reference count
   1748  * Parameters:
   1749  *    unit  - unit number.
   1750  *    index - L2 entry index.
   1751  * Returns:
   1752  *    SOC_E_XXX
   1753  * Notes:
   1754  */
   1755 int soc_l2x_sr_ref_sync(int unit, int l2_index)
   1756 {
   1757     soc_control_t   *soc = SOC_CONTROL(unit);
   1758     int                 max_index;
   1759 
   1760     LOG_VERBOSE(BSL_LS_SOC_ARL,
   1761                 (BSL_META_U(unit,
   1762                             "soc_l2x_sr_ref_sync: unit=%d index=%d\n"),
   1763                  unit, l2_index));
   1764 
   1765     if (soc->l2x_pid == SAL_THREAD_ERROR) {
   1766         /* thread not running */
   1767         return SOC_E_NONE;
   1768     }
   1769 
   1770     if (l2x_data[unit].l2mem == INVALIDm) {
   1771         return SOC_E_NONE;
   1772     }
   1773 
   1774     max_index = soc_mem_index_max(unit, l2x_data[unit].l2mem);
   1775     if (l2_index > max_index) {
   1776 #ifdef BCM_HURRICANE3_SUPPORT
   1777         if ((SOC_IS_HURRICANE3(unit) || SOC_IS_GREYHOUND2(unit)) &&
   1778             (l2_index & SOC_L2X_GEN_RESP_INDEX_L2_OVERFLOW(unit))) {
   1779             /* Entry learnt in L2_ENTRY_OVERFLOW */
   1780             return SOC_E_NONE;
   1781         }
   1782 #endif /* BCM_HURRICANE3_SUPPORT */
   1783         return SOC_E_PARAM;
   1784     }
   1785     if (l2x_data[unit].shadow_tab == NULL) {
   1786         LOG_WARN(BSL_LS_SOC_ARL,
   1787                     (BSL_META_U(unit,
   1788                                 "soc_l2x_sr_ref_sync: "
   1789                                 "l2x_data[%d].shadow_tab is NULL!!!\n"),
   1790                      unit));
   1791         return SOC_E_NONE;
   1792     }
   1793 
   1794     SHR_BITSET(l2x_data[unit].sr_ref_map, l2_index);
   1795 
   1796     return SOC_E_NONE;
   1797 }
   1798 
   1799 #endif /* BCM_TSN_SUPPORT */
   1800 
   1801 #endif /* BCM_XGS_SWITCH_SUPPORT */