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

l2mod.c (51733B)


      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 
      8 #include <shared/bsl.h>
      9 
     10 #include <sal/core/libc.h>
     11 #include <shared/alloc.h>
     12 #include <sal/core/spl.h>
     13 #include <sal/core/time.h>
     14 #include <shared/bsl.h>
     15 #include <soc/mem.h>
     16 #include <soc/debug.h>
     17 #include <soc/cm.h>
     18 #include <soc/drv.h>
     19 #include <soc/l2x.h>
     20 #if defined(BCM_TRX_SUPPORT)
     21 #include <soc/triumph.h>
     22 #endif /* BCM_TRX_SUPPORT */
     23 
     24 #ifdef BCM_CMICM_SUPPORT
     25 #include <soc/cmicm.h>
     26 #endif
     27 
     28 #ifdef BCM_XGS3_SWITCH_SUPPORT
     29 
     30 /****************************************************************************
     31  *
     32  * L2MOD Message Registration
     33  */
     34 
     35 #define OPER_WRITE      0
     36 #define OPER_PPA        2
     37 #define OPER_DELETE     3
     38 
     39 #define REASON_CPU      0
     40 #define REASON_AGE      1
     41 #define REASON_PPA      3
     42 
     43 #define REASON_CPU       0
     44 #define REASON_LEARN     1
     45 #define REASON_STAT_MOVE 2
     46 #define REASON_PPA       3
     47 
     48 #if defined(BCM_TRX_SUPPORT)
     49 STATIC int
     50 soc_l2_overflow_event_record_set(int unit, int enable) {
     51 
     52 #if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_HURRICANE3_SUPPORT)
     53     uint32 reg;
     54 
     55     if (SOC_IS_TRIDENT(unit) || SOC_IS_HURRICANE3(unit) ||
     56         SOC_IS_GREYHOUND2(unit)) {
     57         SOC_IF_ERROR_RETURN(READ_L2_LEARN_CONTROLr(unit, &reg));
     58         soc_reg_field_set(unit, L2_LEARN_CONTROLr, &reg,
     59                           L2_RECORD_OVERFLOW_ENABLEf, enable & 1);
     60         SOC_IF_ERROR_RETURN(WRITE_L2_LEARN_CONTROLr(unit, reg));
     61         return SOC_E_NONE;
     62     }
     63 #endif
     64     return SOC_E_NONE;
     65 }
     66 #endif /*defined(BCM_TRX_SUPPORT)*/
     67 STATIC int
     68 _soc_l2mod_fifo_enable(int unit, int val)
     69 {
     70     uint32 reg;
     71 #ifdef BCM_TRX_SUPPORT
     72     if (SOC_IS_TRX(unit)) {
     73         SOC_IF_ERROR_RETURN(READ_AUX_ARB_CONTROLr(unit, &reg));
     74         /* Does application cares about MEMWR, L2_INSERT, L2_DELETE ? */
     75         soc_reg_field_set(unit, AUX_ARB_CONTROLr, &reg,
     76                           L2_MOD_FIFO_ENABLE_AGEf, val);
     77         soc_reg_field_set(unit, AUX_ARB_CONTROLr, &reg,
     78                           L2_MOD_FIFO_ENABLE_LEARNf, val);
     79         soc_reg_field_set(unit, AUX_ARB_CONTROLr, &reg,
     80                          L2_MOD_FIFO_ENABLE_L2_DELETEf, val);
     81         if (!soc_feature(unit, soc_feature_l2_bulk_control)) {
     82             soc_reg_field_set(unit, AUX_ARB_CONTROLr, &reg,
     83                               L2_MOD_FIFO_ENABLE_PPA_DELETEf, val);
     84             soc_reg_field_set(unit, AUX_ARB_CONTROLr, &reg,
     85                               L2_MOD_FIFO_ENABLE_PPA_REPLACEf, val);
     86         }
     87         SOC_IF_ERROR_RETURN(WRITE_AUX_ARB_CONTROLr(unit, reg));
     88 
     89         if (soc_feature(unit, soc_feature_l2_bulk_control)) {
     90             SOC_IF_ERROR_RETURN(READ_L2_BULK_CONTROLr(unit, &reg));
     91             soc_reg_field_set(unit, L2_BULK_CONTROLr, &reg,
     92                               L2_MOD_FIFO_RECORDf, 1);
     93             SOC_IF_ERROR_RETURN(WRITE_L2_BULK_CONTROLr(unit, reg));
     94         }
     95 
     96         if (SOC_IS_TRIDENT(unit) || SOC_IS_HURRICANE3(unit) ||
     97             SOC_IS_GREYHOUND2(unit)) {
     98 	        SOC_IF_ERROR_RETURN(soc_l2_overflow_event_record_set(unit, 1));
     99         }
    100         
    101         return SOC_E_NONE;
    102     }
    103 #endif /* BCM_TRX_SUPPORT */
    104 #ifdef BCM_FIREBOLT_SUPPORT
    105     if (SOC_IS_FBX(unit)) {
    106         SOC_IF_ERROR_RETURN(READ_AUX_ARB_CONTROLr(unit, &reg));
    107         soc_reg_field_set(unit, AUX_ARB_CONTROLr, &reg, L2_MOD_FIFO_ENABLEf, val);
    108         SOC_IF_ERROR_RETURN(WRITE_AUX_ARB_CONTROLr(unit, reg));
    109     }
    110 #endif
    111     return SOC_E_NONE;
    112 }
    113 
    114 STATIC int
    115 _soc_l2mod_fifo_lock(int unit, int val)
    116 {
    117     uint32 reg;
    118 #ifdef BCM_FIREBOLT_SUPPORT
    119     if (SOC_IS_FBX(unit)) {
    120         SOC_IF_ERROR_RETURN(READ_AUX_ARB_CONTROLr(unit, &reg));
    121         soc_reg_field_set(unit, AUX_ARB_CONTROLr, &reg, L2_MOD_FIFO_LOCKf, val);
    122         SOC_IF_ERROR_RETURN(WRITE_AUX_ARB_CONTROLr(unit, reg));
    123     }
    124 #endif
    125     return SOC_E_NONE;
    126 }
    127 
    128 STATIC int
    129 _soc_l2mod_fifo_get_count(int unit, int * cnt)
    130 {
    131     uint32 reg;
    132 #ifdef BCM_FIREBOLT_SUPPORT
    133     if (SOC_IS_FBX(unit)) {
    134         SOC_IF_ERROR_RETURN(READ_L2_MOD_FIFO_CNTr(unit, &reg));
    135         *cnt = soc_reg_field_get(unit, L2_MOD_FIFO_CNTr, reg, NUM_OF_ENTRIESf);
    136     }
    137 #endif
    138     return SOC_E_NONE;
    139 }
    140 
    141 
    142 #ifdef BCM_KATANA_SUPPORT
    143  void
    144 _soc_kt_l2mod_fifo_process(int unit, uint32 flags, l2_mod_fifo_entry_t *entry)
    145 {
    146     int operation;
    147     l2x_entry_t l2x_entry, old_l2x_entry;
    148     uint32 fval[SOC_MAX_MEM_FIELD_WORDS];
    149     int len;
    150 
    151     operation = soc_L2_MOD_FIFOm_field32_get(unit, entry, OPERATIONf);
    152     soc_L2_MOD_FIFOm_field_get(unit, entry, L2_ENTRY_DATAf,
    153                                l2x_entry.entry_data);
    154     if (soc_mem_field32_get(unit, L2_MOD_FIFOm, entry, STATION_MOVEf)) {
    155         sal_memcpy(&old_l2x_entry, &l2x_entry, sizeof(l2x_entry));
    156         soc_mem_field_get(unit, L2_MOD_FIFOm, (uint32 *)entry,
    157                           REPLACED_ASSOC_DATAf, fval);
    158         len = soc_mem_field_length(unit, L2Xm, ASSOCIATED_DATAf);
    159         if (len & 0x1f) {
    160             fval[len / 32] &= (1 << (len & 0x1f)) - 1;
    161         }
    162         soc_mem_field_set(unit, L2Xm, (uint32 *)&old_l2x_entry,
    163                           ASSOCIATED_DATAf, fval);
    164     }
    165 
    166     switch (operation) {
    167     case 0: /* L2_DELETE */
    168     case 1: /* PPA DELETE */
    169     case 2: /* AGE */
    170     case 9: /* L2_BULK_DELETE */
    171     case 11: /* L2_BULK_AGE */
    172         soc_l2x_callback(unit, 0, &l2x_entry, NULL);
    173         break;
    174     case 10: /* L2_BULK_REPLACE */
    175     case  4: /* PPA REPLACE */
    176         soc_l2x_callback(unit, 0, &old_l2x_entry, &l2x_entry);
    177         break;
    178     case 3: /* L2_INSERT */
    179     case 5: /* LEARN */
    180 
    181         if (soc_mem_field32_get(unit, L2_MOD_FIFOm, entry, STATION_MOVEf)) {
    182             soc_l2x_callback(unit, 0, &old_l2x_entry, &l2x_entry);
    183         } else {
    184             soc_l2x_callback(unit, 0, NULL, &l2x_entry);
    185         }
    186 
    187         break;
    188     case 6: /* MEMWR, S/W mark for the end of matched traverse */
    189         soc_l2x_callback(unit, SOC_L2X_ENTRY_DUMMY, NULL, NULL);   
    190         break;   
    191     case 8: /* L2_BULK_NO_ACTION */   
    192         soc_l2x_callback(unit, SOC_L2X_ENTRY_NO_ACTION, NULL, &l2x_entry);   
    193         break;   
    194     case 7: /* OVERFLOW */ 
    195     case 12: /* MAC_LIMIT_DELETE_FOR_INSERT */
    196     case 13: /* MAC_LIMIT_DELETE_FOR_PPA_REPLACE */
    197     case 14: /* MAC_LIMIT_DELETE_FOR_LEARN */
    198     default:
    199         break;
    200     }
    201 
    202     if (bsl_check(bslLayerSoc, bslSourceDma, bslSeverityVerbose, unit)) {
    203         soc_mem_entry_dump(unit, L2_MOD_FIFOm, entry, BSL_VERBOSE|BSL_LS_SOC_DMA);
    204         LOG_VERBOSE(BSL_LS_SOC_DMA, (BSL_META_U(unit, "\n")));
    205     }
    206 }
    207 #endif /* BCM_KATANA_SUPPORT */
    208 
    209 #ifdef BCM_TRIDENT2_SUPPORT
    210 void
    211 _soc_td2_l2mod_fifo_process(int unit, uint32 flags, l2_mod_fifo_entry_t *entry)
    212 {
    213     int operation;
    214     l2x_entry_t l2x_entry, old_l2x_entry;
    215     uint32 fval[SOC_MAX_MEM_FIELD_WORDS];
    216     int len;
    217     soc_field_t vld_fld = VALIDf;
    218     soc_field_t data_fld = ASSOCIATED_DATAf;
    219 
    220 #ifdef BCM_TOMAHAWK_SUPPORT
    221     if (SOC_IS_TOMAHAWKX(unit)) {
    222         data_fld = L2__ASSOCIATED_DATAf;
    223     }
    224 #endif
    225 
    226     if (soc_feature(unit, soc_feature_base_valid)) {
    227         vld_fld = BASE_VALIDf;
    228     }
    229 
    230     operation = soc_L2_MOD_FIFOm_field32_get(unit, entry, OPERATIONf);
    231     if (SOC_MEM_FIELD_VALID(unit, L2_MOD_FIFOm, L2_ENTRY_DATAf)) { 
    232         soc_L2_MOD_FIFOm_field_get(unit, entry, L2_ENTRY_DATAf,
    233                                   l2x_entry.entry_data); 
    234     } else { 
    235         soc_L2_MOD_FIFOm_field_get(unit, entry, L2_ENTRYf,
    236                                    l2x_entry.entry_data); 
    237     }
    238     if (soc_mem_field32_get(unit, L2_MOD_FIFOm, entry, STATION_MOVEf)) {
    239         sal_memcpy(&old_l2x_entry, &l2x_entry, sizeof(l2x_entry));
    240         soc_mem_field_get(unit, L2_MOD_FIFOm, (uint32 *)entry,
    241                           REPLACED_ASSOC_DATAf, fval);
    242         len = soc_mem_field_length(unit, L2Xm, ASSOCIATED_DATAf);
    243         if (len & 0x1f) {
    244             fval[len / 32] &= (1 << (len & 0x1f)) - 1;
    245         }
    246         soc_mem_field_set(unit, L2Xm, (uint32 *)&old_l2x_entry,
    247                           data_fld, fval);
    248     }
    249 
    250     switch (operation) {
    251     case 0: /* L2_DELETE */
    252     case 4: /* AGE */
    253     case 6: /* L2_BULK_DELETE */
    254     case 8: /* L2_BULK_AGE */
    255         soc_l2x_callback(unit, 0, &l2x_entry, NULL);
    256         break;
    257     case 7: /* L2_BULK_REPLACE */
    258         if (SOC_IS_TD2_TT2(unit) &&
    259             (!soc_mem_field32_get(unit, L2Xm, &l2x_entry, vld_fld) &&
    260             sal_memcmp(&l2x_entry, soc_mem_entry_null(unit, L2Xm), sizeof(l2x_entry_t)))) { /* L2_BULK_REPLACE FOR DELETE/AGE */
    261             soc_l2x_callback(unit, 0, &l2x_entry, NULL);
    262         } else {
    263             soc_l2x_callback(unit, 0, &old_l2x_entry, &l2x_entry);
    264         }
    265         break;
    266     case 1: /* L2_INSERT */
    267     case 2: /* LEARN */
    268 
    269         if (soc_mem_field32_get(unit, L2_MOD_FIFOm, entry, STATION_MOVEf)) {
    270             soc_l2x_callback(unit, 0, &old_l2x_entry, &l2x_entry);
    271         } else {
    272         soc_l2x_callback(unit, 0, NULL, &l2x_entry);
    273         }
    274 
    275         break;
    276     case 3: /* MEMWR, S/W mark for the end of matched traverse */
    277         soc_l2x_callback(unit, SOC_L2X_ENTRY_DUMMY, NULL, NULL);
    278         break;
    279     case 5: /* L2_BULK_NO_ACTION */
    280         soc_l2x_callback(unit, SOC_L2X_ENTRY_NO_ACTION, NULL, &l2x_entry);
    281         break;
    282     default:
    283         break;
    284     }
    285 
    286     if (bsl_check(bslLayerSoc, bslSourceDma, bslSeverityVerbose, unit)) {
    287         soc_mem_entry_dump(unit, L2_MOD_FIFOm, entry, BSL_VERBOSE|BSL_LS_SOC_DMA);
    288         LOG_VERBOSE(BSL_LS_SOC_DMA, (BSL_META_U(unit, "\n")));
    289     }
    290 }
    291 #endif /* BCM_TRIDENT2_SUPPORT */
    292 
    293 #ifdef BCM_TRIDENT_SUPPORT
    294 STATIC void
    295 _soc_td_l2mod_fifo_process(int unit, uint32 flags, l2_mod_fifo_entry_t *entry,
    296 			        uint32 *poverflow_event_counter, uint32 overflow_event_threshhold)
    297 {
    298     int operation;
    299     l2x_entry_t l2x_entry, old_l2x_entry;
    300     uint32 fval[SOC_MAX_MEM_FIELD_WORDS];
    301     int len;
    302 
    303     operation = soc_L2_MOD_FIFOm_field32_get(unit, entry, OPERATIONf);
    304     soc_L2_MOD_FIFOm_field_get(unit, entry, L2_ENTRY_DATAf,
    305                                l2x_entry.entry_data);
    306     if (soc_mem_field32_get(unit, L2_MOD_FIFOm, entry, STATION_MOVEf)) {
    307         sal_memcpy(&old_l2x_entry, &l2x_entry, sizeof(l2x_entry));
    308         soc_mem_field_get(unit, L2_MOD_FIFOm, (uint32 *)entry,
    309                           REPLACED_ASSOC_DATAf, fval);
    310         len = soc_mem_field_length(unit, L2Xm, ASSOCIATED_DATAf);
    311         if (len & 0x1f) {
    312             fval[len / 32] &= (1 << (len & 0x1f)) - 1;
    313         }
    314         soc_mem_field_set(unit, L2Xm, (uint32 *)&old_l2x_entry,
    315                           ASSOCIATED_DATAf, fval);
    316     }
    317 
    318     switch (operation) {
    319     case 0: /* L2_DELETE */
    320     case 1: /* AGE */
    321     case 7: /* L2_BULK_DELETE */
    322     case 9: /* L2_BULK_AGE */
    323         soc_l2x_callback(unit, 0, &l2x_entry, NULL);
    324         break;
    325     case 8: /* L2_BULK_REPLACE */
    326         soc_l2x_callback(unit, 0, &old_l2x_entry, &l2x_entry);
    327         break;
    328     case 2: /* L2_INSERT */
    329     case 3: /* LEARN */
    330         if (soc_mem_field32_get(unit, L2_MOD_FIFOm, entry, STATION_MOVEf)) {
    331             soc_l2x_callback(unit, 0, &old_l2x_entry, &l2x_entry);
    332         } else {
    333             soc_l2x_callback(unit, 0, NULL, &l2x_entry);
    334         }
    335         break;
    336     case 4: /* MEMWR, S/W mark for the end of matched traverse */
    337         soc_l2x_callback(unit, SOC_L2X_ENTRY_DUMMY, NULL, NULL);
    338         break;
    339     case 5: /* OVERFLOW */
    340         if (SOC_IS_TRIDENT(unit)) {        
    341             (*poverflow_event_counter)++;
    342             if (*poverflow_event_counter < overflow_event_threshhold) {
    343     	        soc_l2x_callback(unit, SOC_L2X_ENTRY_OVERFLOW, NULL, &l2x_entry);
    344             } else if (*poverflow_event_counter == overflow_event_threshhold) {
    345     	        (void)soc_l2_overflow_event_record_set(unit, 0);
    346             }
    347         }
    348       break;
    349     case 6: /* L2_BULK_NO_ACTION */
    350         soc_l2x_callback(unit, SOC_L2X_ENTRY_NO_ACTION, NULL, &l2x_entry);
    351         break;
    352     default:
    353         break;
    354     }
    355 
    356     if (bsl_check(bslLayerSoc, bslSourceDma, bslSeverityVerbose, unit)) {
    357         soc_mem_entry_dump(unit, L2_MOD_FIFOm, entry, BSL_VERBOSE|BSL_LS_SOC_DMA);
    358         LOG_VERBOSE(BSL_LS_SOC_DMA, (BSL_META_U(unit, "\n")));
    359     }
    360 }
    361 #endif /* BCM_TRIDENT_SUPPORT */
    362 
    363 #if defined(BCM_TRX_SUPPORT)
    364 STATIC void
    365 _soc_tr_l2mod_fifo_process(int unit, uint32 flags, l2_mod_fifo_entry_t *entry)
    366 {
    367     int operation;
    368     l2x_entry_t l2x_entry, old_l2x_entry;
    369     uint32 fval[SOC_MAX_MEM_FIELD_WORDS];
    370     int len = 0;
    371 #ifdef BCM_TRIUMPH_SUPPORT
    372     int rv, rv1;
    373     int index;
    374     ext_l2_entry_entry_t ext_l2_entry, old_ext_l2_entry;
    375 #endif /* BCM_TRIUMPH_SUPPORT */
    376 
    377     operation = soc_L2_MOD_FIFOm_field32_get(unit, entry, OPERATIONf);
    378     soc_L2_MOD_FIFOm_field_get(unit, entry, L2_ENTRY_DATAf,
    379                                l2x_entry.entry_data);
    380     if (soc_mem_field32_get(unit, L2_MOD_FIFOm, entry, STATION_MOVEf)) {
    381         sal_memcpy(&old_l2x_entry, &l2x_entry, sizeof(l2x_entry));
    382         soc_mem_field_get(unit, L2_MOD_FIFOm, (uint32 *)entry,
    383                           REPLACED_ASSOC_DATAf, fval);
    384         len = soc_mem_field_length(unit, L2Xm, ASSOCIATED_DATAf);
    385         if (len & 0x1f) {
    386             fval[len / 32] &= (1 << (len & 0x1f)) - 1;
    387         }
    388         soc_mem_field_set(unit, L2Xm, (uint32 *)&old_l2x_entry,
    389                           ASSOCIATED_DATAf, fval);
    390     }
    391 
    392     switch (operation) {
    393     case 1: /* PPA_DELETE */
    394     case 2: /* AGE */
    395         soc_l2x_callback(unit, 0, &l2x_entry, NULL);
    396         break;
    397     case 4: /* PPA_REPLACE */
    398         soc_l2x_callback(unit, 0, &old_l2x_entry, &l2x_entry);
    399         break;
    400     case 5: /* LEARN */
    401 #ifdef BCM_TRIUMPH_SUPPORT
    402         /* Check if it is a FALSE station move */
    403         if (soc_mem_field32_get(unit, L2_MOD_FIFOm, entry, STATION_MOVEf)) {
    404             uint32 fval_new[SOC_MAX_MEM_FIELD_WORDS];
    405 
    406             /* Get associated data of new entry,
    407                we already have assc data of old_entry in fval from above */
    408             soc_mem_field_get(unit, L2Xm, (uint32 *)&l2x_entry,
    409                               ASSOCIATED_DATAf, fval_new);
    410             if (!(sal_memcmp(fval, fval_new, BITS2BYTES(len)))) {
    411                 /* If old data is same as new data the its a FALSE move */
    412                 break;
    413             }
    414         }
    415 
    416         if (soc_mem_is_valid(unit, EXT_L2_ENTRYm) &&
    417             soc_mem_index_count(unit, EXT_L2_ENTRYm) > 0 &&
    418             !soc_mem_field32_get(unit, L2Xm, &l2x_entry, PENDINGf)) {
    419             soc_triumph_l2x_to_ext_l2(unit, &l2x_entry, &ext_l2_entry);
    420 
    421             soc_mem_lock(unit, L2Xm);
    422             soc_mem_lock(unit, EXT_L2_ENTRYm);
    423             rv = soc_mem_generic_lookup(unit, EXT_L2_ENTRYm, MEM_BLOCK_ANY, 0,
    424                                         &ext_l2_entry, &old_ext_l2_entry,
    425                                         NULL);
    426             if (SOC_SUCCESS(rv)) {
    427                 if (soc_mem_field32_get(unit, EXT_L2_ENTRYm,
    428                                         &old_ext_l2_entry, STATIC_BITf)) {
    429                     /*
    430                      * If an static entry for the same lookup key has been
    431                      * inserted to external table before we have chance to
    432                      * process the learn event.
    433                      * Ignore the learn event, no call back.
    434                      */
    435                     soc_mem_unlock(unit, L2Xm);
    436                     soc_mem_unlock(unit, EXT_L2_ENTRYm);
    437                     break;
    438                 }
    439             } 
    440             rv = soc_mem_generic_insert(unit, EXT_L2_ENTRYm, MEM_BLOCK_ANY, 0,
    441                                         &ext_l2_entry, &old_ext_l2_entry,
    442                                         NULL);
    443             if (SOC_SUCCESS(rv) || rv == SOC_E_EXISTS) {
    444                 int is_static;
    445                 rv1 = soc_mem_generic_lookup(unit, L2Xm, MEM_BLOCK_ANY, 0,
    446                                              &l2x_entry, &old_l2x_entry,
    447                                              &index);
    448                 is_static = soc_mem_field32_get(unit, L2Xm, &old_l2x_entry, 
    449                                                 STATIC_BITf);
    450                 if ((SOC_SUCCESS(rv1) && is_static) || 
    451                     ((rv1 == SOC_E_NOT_FOUND) && SOC_SUCCESS(rv))) {
    452                     /*
    453                      * If either an static entry for the same lookup key has
    454                      * been inserted to internal table or the entry has been
    455                      * delete from internal table before we have chance to
    456                      * process the mod fifo learn event.
    457                      * Ignore the learn event (undo insert), no call back.
    458                      */
    459                     soc_mem_generic_delete(unit, EXT_L2_ENTRYm, MEM_BLOCK_ANY,
    460                                            0, &ext_l2_entry, NULL, NULL);
    461                     soc_mem_unlock(unit, L2Xm);
    462                     soc_mem_unlock(unit, EXT_L2_ENTRYm);
    463                     break;
    464                 }
    465                 if (SOC_SUCCESS(rv1)) {
    466                     (void)soc_mem_field32_modify(unit, L2Xm, index,
    467                                                  LIMIT_COUNTEDf, 0);
    468                     (void)soc_mem_generic_delete(unit, L2Xm, MEM_BLOCK_ANY,
    469                                                  0, &l2x_entry, NULL, NULL);
    470                     if (rv == SOC_E_EXISTS ) {
    471                         /* Update counts as its a move (while using ESM) */
    472                         soc_triumph_learn_count_update(unit, &old_ext_l2_entry,
    473                                                        FALSE, -1);
    474                     }
    475                 }
    476                 soc_mem_unlock(unit, L2Xm);
    477                 soc_mem_unlock(unit, EXT_L2_ENTRYm);
    478 
    479                 if (rv == SOC_E_EXISTS) {
    480                     /* Do extra delete callback if the entry exists in ext
    481                      * table but has "deleted" mark. */
    482                     if (!soc_mem_field32_get(unit, EXT_L2_ENTRYm,
    483                                              &old_ext_l2_entry, VALIDf)) {
    484                         soc_triumph_ext_l2_to_l2x(unit, &old_ext_l2_entry,
    485                                                   &old_l2x_entry);
    486                         soc_l2x_callback(unit, 0, &old_l2x_entry, NULL);
    487                     }
    488                 }
    489             } else {
    490                 soc_mem_unlock(unit, L2Xm);
    491                 soc_mem_unlock(unit, EXT_L2_ENTRYm);
    492             }
    493         }
    494 #endif /* BCM_TRIUMPH_SUPPORT */
    495         if (soc_feature(unit, soc_feature_ppa_bypass)) {
    496             if (SOC_CONTROL(unit)->l2x_ppa_bypass == FALSE &&
    497                 soc_mem_field32_get(unit, L2Xm, &l2x_entry, KEY_TYPEf) !=
    498                 TR_L2_HASH_KEY_TYPE_BRIDGE) {
    499                 SOC_CONTROL(unit)->l2x_ppa_bypass = TRUE;
    500             }
    501         }
    502         if (soc_mem_field32_get(unit, L2_MOD_FIFOm, entry, STATION_MOVEf)) {
    503             soc_l2x_callback(unit, 0, &old_l2x_entry, &l2x_entry);
    504         } else {
    505             soc_l2x_callback(unit, 0, NULL, &l2x_entry);
    506         }
    507         break;
    508     case 0: /* L2_DELETE */
    509             soc_l2x_callback(unit, 0, &l2x_entry, NULL);
    510             break;
    511     case 3: /* L2_INSERT */
    512     case 6: /* MEMWR */
    513     case 7: /* OVERFLOW */
    514     case 11: /* MAC_LIMIT_DELETE_FOR_INSERT */
    515     case 12: /* MAC_LIMIT_DELETE_FOR_PPA_REPLACE */
    516     case 13: /* MAC_LIMIT_DELETE_FOR_LEARN */
    517     default:
    518         break;
    519     }
    520 
    521     if (bsl_check(bslLayerSoc, bslSourceDma, bslSeverityVerbose, unit)) {
    522         soc_mem_entry_dump(unit, L2_MOD_FIFOm, entry, BSL_VERBOSE|BSL_LS_SOC_DMA);
    523         LOG_VERBOSE(BSL_LS_SOC_DMA, (BSL_META_U(unit, "\n")));
    524     }
    525 }
    526 
    527 #ifdef BCM_TRIUMPH_SUPPORT
    528 STATIC void
    529 _soc_tr_ext_l2mod_fifo_process(int unit, uint32 flags,
    530                                ext_l2_mod_fifo_entry_t *entry)
    531 {
    532     int rv, typ;
    533     l2x_entry_t l2x_entry, old_l2x_entry;
    534     ext_l2_entry_entry_t ext_l2_entry, old_ext_l2_entry;
    535     ext_l2_entry_tcam_entry_t tcam_entry;
    536     uint32 rval, index;
    537     sal_mac_addr_t mac;
    538     static uint32 repl_t = 0, repl_dest = 0;
    539 
    540     soc_mem_field_get(unit, EXT_L2_MOD_FIFOm, (uint32 *)entry, WR_DATAf,
    541                       (uint32 *)&ext_l2_entry);
    542     index = soc_mem_field32_get(unit, EXT_L2_MOD_FIFOm, entry, ENTRY_ADRf);
    543 
    544     /*
    545      * ESM_L2_AGE_CTL.EN_RD_TCAM and ESM_PER_PORTREPL_CONTROL.EN_RD_TCAM
    546      * are required to be set to same value (even if aging is disable)
    547      */
    548     if (SOC_FAILURE(READ_ESM_L2_AGE_CTLr(unit, &rval))) {
    549         return;
    550     }
    551     if (!soc_reg_field_get(unit, ESM_L2_AGE_CTLr, rval, EN_RD_TCAMf)) {
    552         if (SOC_FAILURE(soc_mem_read(unit, EXT_L2_ENTRY_TCAMm,
    553                                      MEM_BLOCK_ANY, index, &tcam_entry))) {
    554             return;
    555         }
    556         soc_mem_mac_addr_get(unit, EXT_L2_ENTRY_TCAMm, &tcam_entry, MAC_ADDRf,
    557                              mac);
    558         soc_mem_mac_addr_set(unit, EXT_L2_ENTRYm, &ext_l2_entry, MAC_ADDRf,
    559                              mac);
    560     }
    561 
    562     typ = soc_mem_field32_get(unit, EXT_L2_MOD_FIFOm, entry, TYPf);
    563     switch (typ) {
    564     case 3: /* special PPA REPL marker by software */
    565         repl_t = soc_mem_field32_get(unit, EXT_L2_ENTRYm, &ext_l2_entry, Tf);
    566         repl_dest = soc_mem_field32_get(unit, EXT_L2_ENTRYm, &ext_l2_entry,
    567                                         DESTINATIONf);
    568         break;
    569     case 4: /* REPLACED */
    570         sal_memcpy(&old_ext_l2_entry, &ext_l2_entry,
    571                    soc_mem_entry_words(unit, EXT_L2_ENTRYm) * 4);
    572         soc_mem_field32_set(unit, EXT_L2_ENTRYm, &ext_l2_entry, Tf, repl_t);
    573         soc_mem_field32_set(unit, EXT_L2_ENTRYm, &ext_l2_entry, DESTINATIONf,
    574                             repl_dest);
    575         soc_mem_lock(unit, EXT_L2_ENTRYm);
    576         soc_triumph_learn_count_update(unit, &ext_l2_entry, FALSE, 1);
    577         
    578         soc_triumph_ext_l2_entry_update(unit, index, &ext_l2_entry);
    579         soc_triumph_learn_count_update(unit, &old_ext_l2_entry, FALSE, -1);
    580         soc_mem_unlock(unit, EXT_L2_ENTRYm);
    581         soc_triumph_ext_l2_to_l2x(unit, &old_ext_l2_entry, &old_l2x_entry);
    582         soc_triumph_ext_l2_to_l2x(unit, &ext_l2_entry, &l2x_entry);
    583         soc_l2x_callback(unit, 0, &old_l2x_entry, &l2x_entry);
    584         break;
    585     case 5: /* DELETED */
    586     case 6: /* ENTRY_IS_OLD */
    587         soc_mem_lock(unit, EXT_L2_ENTRYm);
    588         soc_triumph_ext_l2_entry_update(unit, index, NULL);
    589         soc_triumph_learn_count_update(unit, &ext_l2_entry, TRUE, -1);
    590         soc_mem_unlock(unit, EXT_L2_ENTRYm);
    591         soc_triumph_ext_l2_to_l2x(unit, &ext_l2_entry, &l2x_entry);
    592         soc_l2x_callback(unit, 0, &l2x_entry, NULL);
    593         break;
    594     case 7: /* CLEARED_VALID */
    595         rv = soc_mem_generic_lookup(unit, EXT_L2_ENTRYm, MEM_BLOCK_ANY, 0,
    596                                     &ext_l2_entry, &old_ext_l2_entry, 0);
    597         if (rv != SOC_E_NONE) {
    598             return;
    599         }
    600 
    601         /* delete only if the VALID bit is cleared */
    602         if (soc_mem_field32_get(unit, EXT_L2_ENTRYm, &old_ext_l2_entry,
    603             VALIDf)) {
    604             return;
    605         }
    606 
    607         soc_mem_generic_delete(unit, EXT_L2_ENTRYm, MEM_BLOCK_ANY, 0,
    608                                &ext_l2_entry, NULL, 0);
    609         soc_triumph_learn_count_update(unit, &ext_l2_entry, TRUE, -1);
    610         soc_triumph_ext_l2_to_l2x(unit, &ext_l2_entry, &l2x_entry);
    611         soc_l2x_callback(unit, 0, &l2x_entry, NULL);
    612         break;
    613     default:
    614         break;
    615     }
    616 }
    617 #endif /* BCM_TRIUMPH_SUPPORT */
    618 #endif /* BCM_TRX_SUPPORT */
    619 
    620 #if defined(BCM_TSN_SUPPORT)
    621  void
    622 _soc_gh2_tsn_l2mod_fifo_process(
    623     int unit,
    624     uint32 flags,
    625     l2_mod_fifo_entry_t *entry)
    626 {
    627     int operation;
    628     l2x_entry_t l2x_entry, old_l2x_entry;
    629     uint32 fval[SOC_MAX_MEM_FIELD_WORDS];
    630     int len;
    631     l2x_entry_t l2x_entry_sr;
    632     int is_tsn_or_sr_flow = FALSE; /* TSN or SR related flow */
    633 
    634     operation = soc_L2_MOD_FIFOm_field32_get(unit, entry, OPERATIONf);
    635     soc_L2_MOD_FIFOm_field_get(unit, entry, L2_ENTRY_DATAf,
    636                                l2x_entry.entry_data);
    637     if (soc_mem_field32_get(unit, L2_MOD_FIFOm, entry, STATION_MOVEf)) {
    638         sal_memcpy(&old_l2x_entry, &l2x_entry, sizeof(l2x_entry));
    639         soc_mem_field_get(unit, L2_MOD_FIFOm, (uint32 *)entry,
    640                           REPLACED_ASSOC_DATAf, fval);
    641         len = soc_mem_field_length(unit, L2Xm, ASSOCIATED_DATAf);
    642         if (len & 0x1f) {
    643             fval[len / 32] &= (1 << (len & 0x1f)) - 1;
    644         }
    645         soc_mem_field_set(unit, L2Xm, (uint32 *)&old_l2x_entry,
    646                           ASSOCIATED_DATAf, fval);
    647     }
    648 
    649     /* Need to get SR_L2_ENTRY_DATA for TSN/SR L2MOD FIFO support */
    650     sal_memcpy(&l2x_entry_sr, &l2x_entry, sizeof(l2x_entry));
    651     soc_L2_MOD_FIFOm_field_get(unit, entry,
    652                                SR_L2_ENTRY_DATAf, fval);
    653     len = soc_mem_field_length(unit, L2Xm, SR_ASSOCIATED_DATAf);
    654     if (len & 0x1f) {
    655         fval[len / 32] &= (1 << (len & 0x1f)) - 1;
    656     }
    657     soc_L2Xm_field_set(unit, &l2x_entry_sr,
    658                        SR_ASSOCIATED_DATAf, fval);
    659 
    660     if ((soc_L2Xm_field32_get(unit, &l2x_entry_sr, TSN_CIRCUIT_IDf) != 0) ||
    661         (soc_L2Xm_field32_get(unit, &l2x_entry_sr, SR_FLOW_IDf) != 0)) {
    662         is_tsn_or_sr_flow = TRUE;
    663     }
    664 
    665     switch (operation) {
    666         case 0: /* L2_DELETE */
    667         case 1: /* PPA DELETE */
    668             soc_l2x_callback(unit, SOC_L2X_ENTRY_DELETE, &l2x_entry, NULL);
    669             break;
    670         case 2: /* AGE */
    671             if (is_tsn_or_sr_flow == TRUE) {
    672                 /* Decrease TSN/SR flowset reference count for PPA/AGE deletion */
    673                 soc_l2x_callback(unit,
    674                                  SOC_L2X_ENTRY_TSN_SR_FLOWSET_REF_CNT,
    675                                  &l2x_entry_sr, NULL);
    676             }
    677             soc_l2x_callback(unit, SOC_L2X_ENTRY_AGE, &l2x_entry, NULL);
    678             break;
    679         case 4: /* PPA REPLACE */
    680             soc_l2x_callback(unit, SOC_L2X_ENTRY_DELETE, &old_l2x_entry,
    681                              &l2x_entry);
    682             break;
    683         case 3: /* L2_INSERT */
    684             if (soc_mem_field32_get(unit, L2_MOD_FIFOm,
    685                                     entry, STATION_MOVEf)) {
    686                 soc_l2x_callback(unit, SOC_L2X_ENTRY_INSERT, &old_l2x_entry,
    687                                  &l2x_entry);
    688             } else {
    689                 soc_l2x_callback(unit, SOC_L2X_ENTRY_INSERT, NULL, &l2x_entry);
    690             }
    691             break;
    692         case 5: /* LEARN */
    693             if (soc_mem_field32_get(unit, L2_MOD_FIFOm,
    694                                     entry, STATION_MOVEf)) {
    695                 soc_l2x_callback(unit, SOC_L2X_ENTRY_LEARN, &old_l2x_entry,
    696                                  &l2x_entry);
    697             } else {
    698                 if (is_tsn_or_sr_flow == TRUE) {
    699                     /* Increase TSN/SR flowset reference count for addition */
    700                     soc_l2x_callback(unit,
    701                                      SOC_L2X_ENTRY_TSN_SR_FLOWSET_REF_CNT,
    702                                      NULL, &l2x_entry_sr);
    703                 }
    704                 soc_l2x_callback(unit, SOC_L2X_ENTRY_LEARN, NULL, &l2x_entry);
    705             }
    706             break;
    707         case 7: /* OVERFLOW */
    708             soc_l2x_callback(unit, SOC_L2X_ENTRY_OVERFLOW, NULL, &l2x_entry);
    709             break;
    710         case 6: /* MEMWR */
    711         case 11: /* MAC_LIMIT_DELETE_FOR_INSERT */
    712         case 12: /* MAC_LIMIT_DELETE_FOR_PPA_REPLACE */
    713         case 13: /* MAC_LIMIT_DELETE_FOR_LEARN */
    714         default:
    715             break;
    716     }
    717 
    718     if (bsl_check(bslLayerSoc, bslSourceDma, bslSeverityVerbose, unit)) {
    719         soc_mem_entry_dump(unit, L2_MOD_FIFOm, entry, BSL_VERBOSE|BSL_LS_SOC_DMA);
    720         LOG_VERBOSE(BSL_LS_SOC_DMA, (BSL_META_U(unit,
    721                             "\n")));
    722     }
    723 }
    724 #endif /* BCM_TSN_SUPPORT */
    725 
    726 #ifdef BCM_HURRICANE2_SUPPORT
    727  void
    728 _soc_hu2_l2mod_fifo_process(int unit, uint32 flags,
    729     l2_mod_fifo_entry_t *entry)
    730 {
    731     int operation;
    732     l2x_entry_t l2x_entry, old_l2x_entry;
    733     uint32 fval[SOC_MAX_MEM_FIELD_WORDS];
    734     int len;
    735 
    736 #if defined(BCM_TSN_SUPPORT)
    737     if (soc_feature(unit, soc_feature_tsn)) {
    738         _soc_gh2_tsn_l2mod_fifo_process(unit, flags, entry);
    739     } else
    740 #endif /* BCM_TSN_SUPPORT */
    741     {
    742         operation = soc_L2_MOD_FIFOm_field32_get(unit, entry, OPERATIONf);
    743         soc_L2_MOD_FIFOm_field_get(unit, entry, L2_ENTRY_DATAf,
    744                                    l2x_entry.entry_data);
    745         if (soc_mem_field32_get(unit, L2_MOD_FIFOm, entry, STATION_MOVEf)) {
    746             sal_memcpy(&old_l2x_entry, &l2x_entry, sizeof(l2x_entry));
    747             soc_mem_field_get(unit, L2_MOD_FIFOm, (uint32 *)entry,
    748                               REPLACED_ASSOC_DATAf, fval);
    749             len = soc_mem_field_length(unit, L2Xm, ASSOCIATED_DATAf);
    750             if (len & 0x1f) {
    751                 fval[len / 32] &= (1 << (len & 0x1f)) - 1;
    752             }
    753             soc_mem_field_set(unit, L2Xm, (uint32 *)&old_l2x_entry,
    754                               ASSOCIATED_DATAf, fval);
    755         }
    756 
    757         switch (operation) {
    758             case 0: /* L2_DELETE */
    759             case 1: /* PPA DELETE */
    760                 soc_l2x_callback(unit, SOC_L2X_ENTRY_DELETE, &l2x_entry, NULL);
    761                 break;
    762             case 2: /* AGE */
    763                 soc_l2x_callback(unit, SOC_L2X_ENTRY_AGE, &l2x_entry, NULL);
    764                 break;
    765             case 4: /* PPA REPLACE */
    766                 soc_l2x_callback(unit, SOC_L2X_ENTRY_DELETE, &old_l2x_entry,
    767                                  &l2x_entry);
    768                 break;
    769             case 3: /* L2_INSERT */
    770                 if (soc_mem_field32_get(unit, L2_MOD_FIFOm,
    771                                         entry, STATION_MOVEf)) {
    772                     soc_l2x_callback(unit, SOC_L2X_ENTRY_INSERT,
    773                                      &old_l2x_entry, &l2x_entry);
    774                 } else {
    775                     soc_l2x_callback(unit, SOC_L2X_ENTRY_INSERT,
    776                                      NULL, &l2x_entry);
    777                 }
    778                 break;
    779             case 5: /* LEARN */
    780                 if (soc_mem_field32_get(unit, L2_MOD_FIFOm,
    781                                         entry, STATION_MOVEf)) {
    782                     soc_l2x_callback(unit, SOC_L2X_ENTRY_LEARN,
    783                                      &old_l2x_entry, &l2x_entry);
    784                 } else {
    785                     soc_l2x_callback(unit, SOC_L2X_ENTRY_LEARN,
    786                                      NULL, &l2x_entry);
    787                 }
    788                 break;
    789             case 7: /* OVERFLOW */
    790                 soc_l2x_callback(unit, SOC_L2X_ENTRY_OVERFLOW,
    791                                  NULL, &l2x_entry);
    792                 break;
    793             case 6: /* MEMWR */
    794             case 11: /* MAC_LIMIT_DELETE_FOR_INSERT */
    795             case 12: /* MAC_LIMIT_DELETE_FOR_PPA_REPLACE */
    796             case 13: /* MAC_LIMIT_DELETE_FOR_LEARN */
    797             default:
    798                 break;
    799         }
    800 
    801         if (bsl_check(bslLayerSoc, bslSourceDma, bslSeverityVerbose, unit)) {
    802             soc_mem_entry_dump(unit, L2_MOD_FIFOm,
    803                                entry, (BSL_VERBOSE | BSL_LS_SOC_DMA));
    804             LOG_VERBOSE(BSL_LS_SOC_DMA, (BSL_META_U(unit, "\n")));
    805         }
    806     }
    807 }
    808 #endif /* BCM_HURRICANE2_SUPPORT */
    809 
    810 STATIC void
    811 _soc_l2mod_fifo_process(int unit, uint32 flags, l2_mod_fifo_entry_t * entry)
    812 {
    813     int op;
    814     l2x_entry_t wr_data;
    815 
    816     op     = soc_L2_MOD_FIFOm_field32_get(unit, entry, OPERf);
    817 
    818     soc_L2_MOD_FIFOm_field_get(unit, entry, WR_DATAf, wr_data.entry_data);
    819 
    820     /*
    821      * No need to translate. A callback expects an l2x_entry_t, and
    822      * does the translation itselt via mbcm.
    823      */
    824 
    825     /*
    826      * The l2mod_fifo_thread gets _changes_, and doesn't need the shadow
    827      * table; therefore no processing happens here. Just call the callback.
    828      */
    829     switch (op) {
    830         case OPER_DELETE:
    831             soc_l2x_callback(unit, 0, &wr_data, NULL);
    832             break;
    833         case OPER_PPA:
    834             soc_l2x_callback(unit, 0, &wr_data, &wr_data);
    835             break;
    836         case OPER_WRITE:
    837             soc_l2x_callback(unit, 0, NULL, &wr_data);
    838             break;
    839         default:
    840             LOG_ERROR(BSL_LS_SOC_L2,
    841                       (BSL_META_U(unit,
    842                                   "soc_l2mod_fifo_thread: invalid operation\n")));
    843             break;
    844     }
    845 }
    846 
    847 STATIC void
    848 _soc_l2mod_thread(void * unit_vp)
    849 {
    850     int unit = PTR_TO_INT(unit_vp);
    851     soc_control_t * soc = SOC_CONTROL(unit);
    852     uint32 *fifo;
    853     int mfifo_words = soc_mem_entry_words(unit, L2_MOD_FIFOm);
    854     int count;
    855     uint32 i;
    856     int interval;
    857     int rv;
    858     uint32 index_min, index_max;
    859 
    860     count = soc_mem_index_count(unit, L2_MOD_FIFOm);
    861     index_min = soc_mem_index_min(unit, L2_MOD_FIFOm);
    862     index_max = soc_mem_index_max(unit, L2_MOD_FIFOm);
    863     fifo = soc_cm_salloc(unit,
    864                          WORDS2BYTES(mfifo_words) * count,
    865                          "L2_MOD_FIFOm");
    866     if (fifo == NULL) {
    867         soc->l2x_pid = SAL_THREAD_ERROR;
    868         soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
    869                            SOC_SWITCH_EVENT_THREAD_L2MOD, __LINE__, 
    870                            SOC_E_MEMORY);
    871         sal_thread_exit(0);
    872         return;
    873     }
    874 
    875     soc_intr_enable(unit, IRQ_L2_MOD_FIFO_NOT_EMPTY);
    876     _soc_l2mod_fifo_enable(unit, 1);
    877     
    878     while ((interval = soc->l2x_interval) != 0) {
    879         /*
    880          * Post the semaphore -- it will be signalled by the ISR when
    881          * new data appear in MOD_FIFO.
    882          */
    883         sal_sem_take(soc->arl_notify, interval);
    884 
    885         /* Lock the fifo */
    886         _soc_l2mod_fifo_lock(unit, 1);
    887 
    888         /* Get the number of entries */
    889         _soc_l2mod_fifo_get_count(unit, &count);
    890 
    891         if (count == 0) {
    892             _soc_l2mod_fifo_lock(unit, 0);
    893             continue;
    894         }
    895 
    896         /* Read in the fifo contents */
    897         if ((rv = soc_mem_read_range(unit, L2_MOD_FIFOm, MEM_BLOCK_ANY,
    898                         index_min, index_max, fifo)) < 0) {
    899             LOG_ERROR(BSL_LS_SOC_L2,
    900                       (BSL_META_U(unit,
    901                                   "AbnormalThreadExit:soc_l2mod_fifo_thread,DMA failed: %s\n"),
    902                        soc_errmsg(rv)));
    903             soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
    904                                SOC_SWITCH_EVENT_THREAD_L2MOD, __LINE__, rv);
    905                 goto cleanup_exit;
    906             }
    907         /* Unlock (and clear) the fifo */
    908         _soc_l2mod_fifo_lock(unit, 0);
    909 
    910         /* Do the callback for each entry */
    911         for (i = index_min; i < (index_min + count); i++) {
    912             if (!soc->l2x_interval) {
    913                 goto cleanup_exit;
    914             }
    915             _soc_l2mod_fifo_process(
    916                             unit,
    917                             soc->l2x_flags,
    918                             (l2_mod_fifo_entry_t *)(fifo + i * mfifo_words));
    919         }
    920         /*
    921          * Re-enable the interrupt for
    922          * L2MOD FIFO not empty events, disabled in ISR.
    923          * Reset arl_notified before waiting
    924          * on the arl_notify semaphore.
    925          */
    926         soc->arl_notified = 0;
    927         soc_intr_enable(unit, IRQ_L2_MOD_FIFO_NOT_EMPTY);
    928     }
    929 cleanup_exit:
    930     soc_cm_sfree(unit, fifo);
    931     soc->l2x_pid = SAL_THREAD_ERROR;
    932     sal_thread_exit(0);
    933 }
    934 
    935 extern uint32 soc_mem_fifo_delay_value;
    936 
    937 #ifdef BCM_TRX_SUPPORT
    938 STATIC void
    939 _soc_l2mod_dma_thread(void *unit_vp)
    940 {
    941     int unit = PTR_TO_INT(unit_vp);
    942     soc_control_t *soc = SOC_CONTROL(unit);
    943     int rv, entries_per_buf, adv_threshold, interval, count, i, non_empty;
    944     int chan[2], entry_words[2];
    945     void *host_buf[2], *host_entry;
    946     soc_mem_t mem[2];
    947     uint32 intr_mask;
    948 #ifdef BCM_CMICM_SUPPORT
    949     uint32 rval = 0;
    950     uint8 overflow = 0, timeout = 0;
    951     int cmc = SOC_PCI_CMC(unit);
    952 #endif /* BCM_CMICM_SUPPORT */
    953 #ifdef BCM_TRIDENT_SUPPORT
    954     uint32 overflow_event_threshhold;
    955     uint32 overflow_event_counter;
    956     sal_usecs_t cur_time, clear_time, time_diff;
    957 #endif
    958 
    959     chan[1] = -1;
    960     mem[1] = INVALIDm;
    961     entry_words[1] = 0;
    962     host_buf[1] = NULL;
    963 
    964     entries_per_buf = soc_property_get(unit, spn_L2XMSG_HOSTBUF_SIZE, 1024);
    965     adv_threshold = entries_per_buf / 2;
    966 
    967     chan[0] = SOC_MEM_FIFO_DMA_CHANNEL_1;
    968     mem[0] = L2_MOD_FIFOm;
    969     entry_words[0] = soc_mem_entry_words(unit, mem[0]);
    970     intr_mask = IRQ_FIFO_CH1_DMA;
    971     host_buf[0] =
    972         soc_cm_salloc(unit, entries_per_buf * entry_words[0] * sizeof(uint32),
    973                       "L2_MOD DMA Buffer");
    974     if (host_buf[0] == NULL) {
    975         soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
    976                            SOC_SWITCH_EVENT_THREAD_L2MOD_DMA, __LINE__, 
    977                            SOC_E_MEMORY);
    978         goto cleanup_exit;
    979     }
    980 
    981 #if defined (BCM_TRIUMPH_SUPPORT)
    982     if (soc_feature(unit, soc_feature_esm_support)) {
    983         chan[1] = SOC_MEM_FIFO_DMA_CHANNEL_2;
    984         mem[1] = EXT_L2_MOD_FIFOm;
    985         entry_words[1] = soc_mem_entry_words(unit, mem[1]);
    986         intr_mask |= IRQ_FIFO_CH2_DMA;
    987         host_buf[1] =
    988             soc_cm_salloc(unit, entries_per_buf * entry_words[1] *
    989                           sizeof(uint32), "EXT_L2_MOD DMA Buffer");
    990         if (host_buf[1] == NULL) {
    991             soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
    992                                SOC_SWITCH_EVENT_THREAD_L2MOD_DMA, __LINE__, 
    993                                SOC_E_MEMORY);
    994             goto cleanup_exit;
    995         }
    996     }
    997 #endif /* BCM_TRIUMPH_SUPPORT */
    998     (void)soc_mem_fifo_dma_stop(unit, chan[0]);
    999     rv = soc_mem_fifo_dma_start(unit, chan[0], mem[0], MEM_BLOCK_ANY,
   1000                                 entries_per_buf, host_buf[0]);
   1001     if (SOC_FAILURE(rv)) {
   1002         soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
   1003                            SOC_SWITCH_EVENT_THREAD_L2MOD_DMA, __LINE__, rv);
   1004         goto cleanup_exit;
   1005     }
   1006 
   1007 #if defined (BCM_TRIUMPH_SUPPORT)
   1008     if (mem[1] != INVALIDm) {
   1009         rv = soc_reg_field32_modify(unit, ESM_L2_AGE_CTLr, REG_PORT_ANY,
   1010                                    CPU_NOTIFYf, 1); 
   1011         if (SOC_FAILURE(rv)) {
   1012             soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
   1013                                SOC_SWITCH_EVENT_THREAD_L2MOD_DMA, __LINE__, rv);
   1014             goto cleanup_exit;
   1015         }
   1016         rv = soc_reg_field32_modify(unit, ESM_PER_PORT_REPL_CONTROLr,
   1017                                    REG_PORT_ANY, CPU_NOTIFYf, 1); 
   1018         if (SOC_FAILURE(rv)) {
   1019             soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
   1020                                SOC_SWITCH_EVENT_THREAD_L2MOD_DMA, __LINE__, rv);
   1021             goto cleanup_exit;
   1022         }
   1023         rv = soc_reg_field32_modify(unit, ESM_CTLr, REG_PORT_ANY,
   1024                                    L2MODFIFO_PUSH_ENf, 1); 
   1025         if (SOC_FAILURE(rv)) {
   1026             soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
   1027                                SOC_SWITCH_EVENT_THREAD_L2MOD_DMA, __LINE__, rv);
   1028             goto cleanup_exit;
   1029         }
   1030         rv = soc_mem_fifo_dma_start(unit, chan[1], mem[1], MEM_BLOCK_ANY,
   1031                                    entries_per_buf, host_buf[1]); 
   1032         if (SOC_FAILURE(rv)) {
   1033             soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
   1034                                SOC_SWITCH_EVENT_THREAD_L2MOD_DMA, __LINE__, rv);
   1035             goto cleanup_exit;
   1036         }
   1037     }
   1038 #endif /* BCM_TRIUMPH_SUPPORT */
   1039     soc_mem_fifo_delay_value =
   1040         soc_property_get(unit, spn_FIFO_DELAY_VALUE, (15 * MILLISECOND_USEC));
   1041 
   1042 #ifdef BCM_TRIDENT_SUPPORT
   1043         overflow_event_threshhold = soc_property_get(unit, "fifo_overflow_threshhold", 100);
   1044         overflow_event_counter = 0;
   1045         clear_time = sal_time_usecs();    
   1046 #endif
   1047 
   1048     _soc_l2mod_fifo_enable(unit, 1);
   1049     
   1050     while ((interval = soc->l2x_interval)) {
   1051         if (soc->l2modDmaIntrEnb) {
   1052 #ifdef BCM_CMICM_SUPPORT
   1053             if (SOC_IS_KATANA(unit)) { 
   1054                 soc_cmicm_intr0_enable(unit, 
   1055                                 IRQ_CMCx_FIFO_CH_DMA(SOC_MEM_FIFO_DMA_CHANNEL_1));
   1056             } else 
   1057 #endif /* BCM_CMICM_SUPPORT */
   1058             {
   1059                 soc_intr_enable(unit, intr_mask);
   1060             }
   1061             if (sal_sem_take(soc->arl_notify, interval) < 0) {
   1062                 LOG_VERBOSE(BSL_LS_SOC_ARL,
   1063                             (BSL_META_U(unit,
   1064                                         "%s polling timeout soc_mem_fifo_delay_value=%d\n"), 
   1065                              soc->l2x_name, soc_mem_fifo_delay_value));
   1066 
   1067 #ifdef BCM_TRIDENT_SUPPORT
   1068                 if (SOC_IS_TRIDENT(unit)) {
   1069                	    overflow_event_counter = 0;
   1070                	    (void)soc_l2_overflow_event_record_set(unit, 1);
   1071                 }
   1072 #endif                    
   1073             } else {
   1074                 LOG_VERBOSE(BSL_LS_SOC_ARL,
   1075                             (BSL_META_U(unit,
   1076                                         "%s woken up soc_mem_fifo_delay_value=%d\n"), 
   1077                              soc->l2x_name, soc_mem_fifo_delay_value));
   1078 #ifdef BCM_CMICM_SUPPORT
   1079                 if (SOC_IS_KATANA(unit)) { 
   1080                      /* check for timeout & overflow */
   1081                     rval = soc_pci_read(unit, 
   1082                               CMIC_CMCx_FIFO_CHy_RD_DMA_STAT_OFFSET(cmc, 
   1083                                               SOC_MEM_FIFO_DMA_CHANNEL_1));          
   1084                     overflow = soc_reg_field_get(unit, 
   1085                                      CMIC_CMC0_FIFO_CH1_RD_DMA_STATr, rval,
   1086                                              FIFO_CH1_DMA_HOSTMEM_TIMEOUTf); 
   1087                     if (overflow) {                         
   1088                         timeout = soc_reg_field_get(unit, 
   1089                                         CMIC_CMC0_FIFO_CH1_RD_DMA_STATr,
   1090                                         rval, FIFO_CH1_DMA_HOSTMEM_OVERFLOWf);
   1091                         overflow |= timeout;
   1092                     }
   1093                 }
   1094 #endif /* BCM_CMICM_SUPPORT */
   1095 #ifdef BCM_TRIDENT_SUPPORT
   1096                 if (SOC_IS_TRIDENT(unit)) {
   1097             		cur_time = sal_time_usecs();
   1098             		time_diff = SAL_USECS_SUB( cur_time, clear_time );
   1099             		if (time_diff > interval) {
   1100             		    overflow_event_counter = 0;
   1101             		    (void)soc_l2_overflow_event_record_set(unit, 1);
   1102             		    clear_time = sal_time_usecs();
   1103                     }
   1104                 }
   1105 #endif                 
   1106             }
   1107         } else {
   1108             sal_usleep(interval);
   1109 #ifdef BCM_TRIDENT_SUPPORT
   1110             if (SOC_IS_TRIDENT(unit)) {            
   1111     	        overflow_event_counter = 0;
   1112         	    (void)soc_l2_overflow_event_record_set(unit, 1);
   1113         	    clear_time = sal_time_usecs();
   1114             }
   1115 #endif              
   1116         }
   1117 
   1118         do {
   1119             non_empty = FALSE;
   1120             rv = soc_mem_fifo_dma_get_read_ptr(unit, chan[0], &host_entry,
   1121                                                &count);
   1122             if (SOC_SUCCESS(rv)) {
   1123                 non_empty = TRUE;
   1124                 if (count > adv_threshold) {
   1125                     count = adv_threshold;
   1126                 }
   1127                 for (i = 0; i < count; i++) {
   1128                     if(!soc->l2x_interval) {
   1129                         goto cleanup_exit;
   1130                     }
   1131 #ifdef BCM_TRIDENT_SUPPORT
   1132                     if (soc_feature(unit, soc_feature_l2_bulk_control)) {
   1133 #ifdef BCM_KATANA_SUPPORT
   1134                          if (SOC_IS_KATANA(unit)) {
   1135                              _soc_kt_l2mod_fifo_process(unit, soc->l2x_flags,
   1136                                                                 host_entry);
   1137 
   1138                          } else
   1139 #endif /* BCM_KATANA_SUPPORT */
   1140                          {
   1141                              _soc_td_l2mod_fifo_process(unit, soc->l2x_flags,
   1142                                                    host_entry,
   1143                                                    &overflow_event_counter, 
   1144                                                    overflow_event_threshhold);
   1145                          }
   1146                     } else
   1147 #endif /* BCM_TRIDENT_SUPPORT */
   1148                     {
   1149                         _soc_tr_l2mod_fifo_process(unit, soc->l2x_flags,
   1150                                                    host_entry);
   1151                     }
   1152                     host_entry = (uint32 *)host_entry + entry_words[0];
   1153                     /*
   1154                      * PPA may wait for available space in mod_fifo, lower the
   1155                      * threshold when ppa is running, therefore read point can
   1156                      * be updated sooner.
   1157                      */
   1158                     if (SOC_CONTROL(unit)->l2x_ppa_in_progress && i >= 63) {
   1159                         i++;
   1160                         break;
   1161                     }
   1162                 }
   1163                 (void)soc_mem_fifo_dma_advance_read_ptr(unit, chan[0], i);
   1164             }
   1165 #if defined(BCM_TRIUMPH_SUPPORT)
   1166             if (mem[1] == INVALIDm) {
   1167                 if (!SOC_CONTROL(unit)->l2x_ppa_in_progress) {
   1168                     sal_thread_yield();
   1169                 }
   1170                 continue;
   1171             }
   1172 
   1173             rv = soc_mem_fifo_dma_get_read_ptr(unit, chan[1], &host_entry,
   1174                                                &count);
   1175             if (SOC_SUCCESS(rv)) {
   1176                 non_empty = TRUE;
   1177                 if (count > adv_threshold) {
   1178                     count = adv_threshold;
   1179                 }
   1180                 for (i = 0; i < count; i++) {
   1181                     if(!soc->l2x_interval) {
   1182                         goto cleanup_exit;
   1183                     }
   1184                     _soc_tr_ext_l2mod_fifo_process(unit, soc->l2x_flags,
   1185                                                    host_entry);
   1186                     host_entry = (uint32 *)host_entry + entry_words[1];
   1187                     /*
   1188                      * PPA may wait for available space in mod_fifo, lower the
   1189                      * threshold when ppa is running, therefore read point can
   1190                      * be updated sooner.
   1191                      */
   1192                     if (SOC_CONTROL(unit)->l2x_ppa_in_progress && i >= 63) {
   1193                         i++;
   1194                         break;
   1195                     }
   1196                 }
   1197                 (void)soc_mem_fifo_dma_advance_read_ptr(unit, chan[1], i);
   1198             }
   1199 #endif /* BCM_TRIUMPH_SUPPORT */
   1200 
   1201             if (!SOC_CONTROL(unit)->l2x_ppa_in_progress) {
   1202                 sal_thread_yield();
   1203             }
   1204         } while (non_empty); 
   1205         /* clearing of the FIFO_CH_DMA_INT interrupt by resetring 
   1206            overflow & timeout status in FIFO_CHx_RD_DMA_STAT_CLR reg */
   1207 #ifdef BCM_CMICM_SUPPORT
   1208             if (SOC_IS_KATANA(unit)) {
   1209                 if (overflow) {
   1210                     rval = 0;
   1211                     soc_reg_field_set(unit, 
   1212                                  CMIC_CMC0_FIFO_CH1_RD_DMA_STAT_CLRr, &rval,
   1213                                           FIFO_CH1_DMA_HOSTMEM_OVERFLOWf, 1);
   1214                     soc_reg_field_set(unit, 
   1215                                  CMIC_CMC0_FIFO_CH1_RD_DMA_STAT_CLRr, &rval,
   1216                                           FIFO_CH1_DMA_HOSTMEM_TIMEOUTf, 1);
   1217                     soc_pci_write(unit, 
   1218                               CMIC_CMCx_FIFO_CHy_RD_DMA_STAT_CLR_OFFSET(cmc, 
   1219                                           SOC_MEM_FIFO_DMA_CHANNEL_1), rval);
   1220                 }
   1221             }
   1222 #endif /* BCM_CMICM_SUPPORT */
   1223         }
   1224 
   1225 cleanup_exit:
   1226     (void)soc_mem_fifo_dma_stop(unit, chan[0]);
   1227 #if defined (BCM_TRIUMPH_SUPPORT)
   1228     if (mem[1] != INVALIDm) {
   1229         (void)soc_mem_fifo_dma_stop(unit, chan[1]);
   1230         (void)soc_reg_field32_modify(unit, ESM_CTLr, REG_PORT_ANY,
   1231                                      L2MODFIFO_PUSH_ENf, 0);
   1232     }
   1233 #endif /* BCM_TRIUMPH_SUPPORT */
   1234 
   1235     if (host_buf[0] != NULL) {
   1236         soc_cm_sfree(unit, host_buf[0]);
   1237     }
   1238     if (mem[1] != INVALIDm && host_buf[1] != NULL) {
   1239         soc_cm_sfree(unit, host_buf[1]);
   1240     }
   1241     /* Exiting L2_MOD_FIFO drain thread, disable recording into L2_MOD_FIFO */
   1242     _soc_l2mod_fifo_enable(unit, 0);
   1243     soc->l2x_pid = SAL_THREAD_ERROR;
   1244     sal_thread_exit(0);
   1245 }
   1246 #endif /* BCM_TRX_SUPPORT */
   1247 #endif /* BCM_XGS3_SWITCH_SUPPORT */
   1248 
   1249 /*
   1250  * Function:
   1251  * 	soc_l2mod_running
   1252  * Purpose:
   1253  *	Determine the L2MOD sync thread running parameters
   1254  * Parameters:
   1255  *	unit - unit number.
   1256  *	flags (OUT) - if non-NULL, receives the current flag settings
   1257  *	interval (OUT) - if non-NULL, receives the current pass interval
   1258  * Returns:
   1259  *   	Boolean; TRUE if L2MOD sync thread is running
   1260  */
   1261 
   1262 int
   1263 soc_l2mod_running(int unit, uint32 *flags, sal_usecs_t *interval)
   1264 {
   1265 #ifdef BCM_XGS3_SWITCH_SUPPORT
   1266     soc_control_t	*soc = SOC_CONTROL(unit);
   1267 
   1268     if (SOC_IS_XGS3_SWITCH(unit)) {
   1269         if (soc->l2x_pid != SAL_THREAD_ERROR) {
   1270             if (flags != NULL) {
   1271                 *flags = soc->l2x_flags;
   1272             }
   1273             if (interval != NULL) {
   1274                 *interval = soc->l2x_interval;
   1275             }
   1276         }
   1277 
   1278         return (soc->l2x_pid != SAL_THREAD_ERROR);
   1279     }
   1280 #endif /* BCM_XGS3_SWITCH_SUPPORT */
   1281     return SOC_E_UNAVAIL;
   1282 }
   1283 
   1284 /*
   1285  * Function:
   1286  * 	soc_l2mod_stop
   1287  * Purpose:
   1288  *   	Stop L2MOD-related thread
   1289  * Parameters:
   1290  *	unit - unit number.
   1291  * Returns:
   1292  *	SOC_E_XXX
   1293  */
   1294 
   1295 int
   1296 soc_l2mod_stop(int unit)
   1297 {
   1298 #ifdef BCM_XGS3_SWITCH_SUPPORT
   1299     soc_control_t * soc = SOC_CONTROL(unit);
   1300     int			rv = SOC_E_NONE;
   1301 
   1302     if (SOC_IS_XGS3_SWITCH(unit)) {
   1303         LOG_INFO(BSL_LS_SOC_ARL,
   1304                  (BSL_META_U(unit,
   1305                              "soc_l2mod_stop: unit=%d\n"), unit));
   1306 
   1307         _soc_l2mod_fifo_enable(unit, 0);
   1308         if (!soc_feature(unit, soc_feature_fifo_dma)) {
   1309             soc_intr_disable(unit, IRQ_L2_MOD_FIFO_NOT_EMPTY);
   1310             /* Wake up thread so it will check the exit flag */
   1311             sal_sem_give(soc->arl_notify);
   1312         }
   1313 #if defined (BCM_TRIUMPH_SUPPORT)
   1314         if (soc_feature(unit, soc_feature_esm_support)) {
   1315             SOC_IF_ERROR_RETURN
   1316                (soc_reg_field32_modify(unit, ESM_L2_AGE_CTLr, REG_PORT_ANY,
   1317                                        CPU_NOTIFYf, 0));
   1318             SOC_IF_ERROR_RETURN
   1319                (soc_reg_field32_modify(unit, ESM_PER_PORT_REPL_CONTROLr,
   1320                                        REG_PORT_ANY, CPU_NOTIFYf, 0));
   1321         }
   1322 #endif /* BCM_TRIUMPH_SUPPORT */
   1323         return rv;
   1324     }
   1325 #endif /* BCM_XGS3_SWITCH_SUPPORT */
   1326     return SOC_E_UNAVAIL;
   1327 }
   1328 
   1329 int
   1330 soc_l2mod_start(int unit, uint32 flags, sal_usecs_t interval)
   1331 {
   1332 #ifdef BCM_XGS3_SWITCH_SUPPORT
   1333     soc_control_t * soc = SOC_CONTROL(unit);
   1334     int             pri;
   1335 
   1336     if (SOC_IS_XGS3_SWITCH(unit)) {
   1337         if (!soc_feature(unit, soc_feature_arl_hashed)) {
   1338             return SOC_E_UNAVAIL;
   1339         }
   1340 
   1341         if (soc->l2x_interval != 0) {
   1342             SOC_IF_ERROR_RETURN(soc_l2mod_stop(unit));
   1343         }
   1344 
   1345         sal_snprintf(soc->l2x_name, sizeof (soc->l2x_name), "bcmL2MOD.%d", unit);
   1346 
   1347         soc->l2x_flags = flags;
   1348         soc->l2x_interval = interval;
   1349 
   1350         if (interval == 0) {
   1351             return SOC_E_NONE;
   1352         }
   1353 
   1354         if (soc->l2x_pid == SAL_THREAD_ERROR) {
   1355             pri = soc_property_get(unit, spn_L2XMSG_THREAD_PRI, 50);
   1356 
   1357 #ifdef BCM_TRX_SUPPORT
   1358             if (soc_feature(unit, soc_feature_fifo_dma)) {
   1359                 soc->l2x_pid =
   1360                     sal_thread_create(soc->l2x_name, SAL_THREAD_STKSZ, pri,
   1361                                       _soc_l2mod_dma_thread, INT_TO_PTR(unit));
   1362             } else
   1363 #endif /* BCM_TRX_SUPPORT */
   1364             {
   1365                 soc->l2x_pid =
   1366                     sal_thread_create(soc->l2x_name, SAL_THREAD_STKSZ, pri,
   1367                                       _soc_l2mod_thread, INT_TO_PTR(unit));
   1368             }
   1369             if (soc->l2x_pid == SAL_THREAD_ERROR) {
   1370                 LOG_ERROR(BSL_LS_SOC_L2,
   1371                           (BSL_META_U(unit,
   1372                                       "soc_l2mod_start: Could not start L2MOD thread\n")));
   1373                 return SOC_E_MEMORY;
   1374             }
   1375         }
   1376 
   1377         return SOC_E_NONE;
   1378     }
   1379 #endif /* BCM_XGS3_SWITCH_SUPPORT */
   1380     return SOC_E_UNAVAIL;
   1381 }