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

memscan.c (86578B)


      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  * Memory Error Scan
      8  *
      9  * This is an optional module that can be used to detect and correct
     10  * memory errors in certain static hardware memories (tables).
     11  *
     12  * Additional CPU time is required to do the scanning.  Table DMA is
     13  * used to reduce this overhead.  The application may choose the overall
     14  * scan rate in entries/sec.
     15  *
     16  * There is also a requirement of additional memory needed to store
     17  * backing caches of the chip memories.  The backing caches are the same
     18  * ones used by the soc_mem_cache() mechanism.  Note that enabling the
     19  * memory cache for frequently updates tables can have significant
     20  * performance benefits.
     21  *
     22  * When the memory scanning thread is enabled, it simply scans all
     23  * memories for which caching is enabled, because these static memories
     24  * are the ones amenable to software error scanning.
     25  */
     26 
     27 
     28 
     29 #include <shared/bsl.h>
     30 
     31 #include <sal/core/libc.h>
     32 
     33 #include <soc/mem.h>
     34 #include <soc/debug.h>
     35 #include <soc/cmic.h>
     36 #include <soc/error.h>
     37 #include <soc/drv.h>
     38 
     39 #ifdef INCLUDE_MEM_SCAN
     40 
     41 #if defined(BCM_TRIDENT2_SUPPORT)
     42 #include <soc/trident2.h>
     43 #endif /* BCM_TRIDENT2_SUPPORT */
     44 #if defined(BCM_TOMAHAWK_SUPPORT)
     45 #include <soc/tomahawk.h>
     46 #endif /* BCM_TOMAHAWK_SUPPORT */
     47 #if defined(BCM_TRIDENT3_SUPPORT)
     48 #include <soc/trident3.h>
     49 #endif
     50 #if defined(SOC_UNIQUE_ACC_TYPE_ACCESS)
     51 #define _SOC_MEMSCAN_UNIQUE_ACC_PIPE_NAME(acc_type) \
     52     ((acc_type) == _SOC_MEM_ADDR_ACC_TYPE_PIPE_1)? "(PIPE_1)" : \
     53     ((acc_type) == _SOC_MEM_ADDR_ACC_TYPE_PIPE_2)? "(PIPE_2)" : \
     54     ((acc_type) == _SOC_MEM_ADDR_ACC_TYPE_PIPE_3)? "(PIPE_3)" : "(PIPE_0)"
     55 #endif /* SOC_UNIQUE_ACC_TYPE_ACCESS */
     56 
     57 STATIC void _soc_mem_scan_thread(void *unit_vp);
     58 #if defined(BCM_TRIDENT2_SUPPORT)
     59 void soc_mem_fp_global_mask_tcam_cache_update(int unit, int chunk_size,
     60                                               uint32 *read_buf);
     61 #endif
     62 static void *_soc_ser_info_p[SOC_MAX_NUM_DEVICES];
     63 static int _soc_ser_info_is_generic[SOC_MAX_NUM_DEVICES];
     64 #if defined(BCM_TRIDENT2_SUPPORT)
     65 static int cache_need_update[SOC_MAX_NUM_DEVICES];
     66 #endif
     67 
     68 typedef struct _soc_mem_scan_table_info_s {
     69     uint32 *xy_tcam_cache;            /* Standard mem cache uses DM encoding
     70                                        * Memscan needs the HW XY encoding. */
     71     SHR_BITDCL *overlay_tcam_bitmap;  /* Which overlay table view is valid
     72                                        * per entry? */
     73     /* Cache table-specific info to avoid recalculating on each pass */
     74     soc_mem_t mem;
     75     uint32 ser_flags; /* read only during runtime */
     76     uint32 entry_dw;
     77     int32 size;
     78     int32 index_min;
     79     int32 index_max;
     80     uint32 mask[SOC_MAX_MEM_WORDS];
     81     uint32 null_entry[SOC_MAX_MEM_WORDS];
     82     uint32 ser_dynamic_state; /* can change during run-time */
     83 } _soc_mem_scan_table_info_t;
     84 
     85 
     86 #define SCAN_INFO_NOT_INITIALIZED 0
     87 #define SCAN_INFO_INITIALIZED     1
     88 
     89 typedef struct _soc_mem_scan_info_s {
     90     int num_tables;
     91     _soc_mem_scan_table_info_t *table_info;
     92     int scan_info_done;
     93 } _soc_mem_scan_info_t;
     94 
     95 static _soc_mem_scan_info_t *scan_info[SOC_MAX_NUM_DEVICES];
     96 
     97 #define _MEM_SCAN_TABLE_INFO(unit, table_index) \
     98     (&(scan_info[(unit)]->table_info[(table_index)]))
     99 
    100 #define _MEM_SCAN_INIT_FLAG_GET(unit) \
    101     (scan_info[(unit)]->scan_info_done)
    102 
    103 #define _MEM_SCAN_INIT_FLAG_SET(unit, init_flag) \
    104         (scan_info[(unit)]->scan_info_done = init_flag)
    105 /*
    106  * Function:
    107  *     soc_mem_scan_ser_list_register
    108  * Purpose:
    109  *       Provide the SER TCAM information list for a device.
    110  * Parameters:
    111  *    unit - StrataSwitch unit # (as a void *).
    112  *    ser_info - Pointer to the _soc_ser_parity_info_t for a device
    113  * Returns:
    114  *    SOC_E_XXX
    115  * Notes:
    116  */
    117 
    118 void
    119 soc_mem_scan_ser_list_register(int unit, int generic, void *ser_info)
    120 {
    121     /* Record the format and pointer for SER TCAM info */
    122     _soc_ser_info_is_generic[unit] = generic;
    123     _soc_ser_info_p[unit] = ser_info;
    124 }
    125 
    126 _soc_generic_ser_info_t *
    127 soc_mem_scan_ser_info_get(int unit)
    128 {
    129     int generic = _soc_ser_info_is_generic[unit];
    130 
    131     if (generic) {
    132         return (_soc_generic_ser_info_t *)_soc_ser_info_p[unit];
    133     } else {
    134         return NULL;
    135     }
    136 }
    137 
    138 /* Emulate the HW SER TCAM engine bit masking */
    139 STATIC void
    140 _soc_mem_scan_ser_tcam_datamask_get(int words, int bits, uint32 *mask_buf)
    141 {
    142     int b;
    143     uint32 tmp;
    144 
    145     for (b = 0; b < words; b++) {
    146         mask_buf[b] = 0;
    147     }
    148 
    149     for (b = 0; b <= bits / 32; b++) {
    150         tmp = -1;
    151 
    152         if (b == 0) {
    153             tmp &= -1;
    154         }
    155 
    156         if (b == bits / 32) {
    157             tmp &= (1 << (bits % 32)) - 1;
    158         }
    159 
    160         /* We check that this is not a Big Endian HW table during SER init */
    161         mask_buf[b] |= tmp;
    162     }
    163 }
    164 
    165 #if defined(BCM_TRIDENT_SUPPORT)
    166 /* Device specific values to interpret FP_GM_FIELDS table */
    167 #define SOC_TD_IFP_LOW_SLICE_SIZE  (128)
    168 #define SOC_TD_IFP_HIGH_SLICE_SIZE  (256)
    169 #define SOC_TD_IFP_LOW_SLICES (4) 
    170 #define SOC_TD2_IFP_LOW_SLICE_SIZE  (512)
    171 #define SOC_TD2_IFP_HIGH_SLICE_SIZE  (256)
    172 #define SOC_TD2_IFP_LOW_SLICES (4)
    173 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
    174 #define SOC_TD2P_IFP_LOW_SLICE_SIZE  (2048)
    175 #define SOC_TD2P_IFP_HIGH_SLICE_SIZE  (1024)
    176 #define SOC_TD2P_IFP_LOW_SLICES (4) 
    177 #endif
    178 #if defined(BCM_APACHE_SUPPORT)
    179 #define SOC_APACHE_IFP_LOW_SLICE_SIZE  (1024)
    180 #define SOC_APACHE_IFP_HIGH_SLICE_SIZE (512)
    181 #define SOC_APACHE_IFP_LOW_SLICES (4)
    182 #endif
    183 #if defined(BCM_MONTEREY_SUPPORT)
    184 #define SOC_MONTEREY_IFP_LOW_SLICE_SIZE  (256)
    185 #define SOC_MONTEREY_IFP_HIGH_SLICE_SIZE (256)
    186 #define SOC_MONTEREY_IFP_LOW_SLICES (12)
    187 #endif
    188 /*
    189  * Function:
    190  * 	_soc_mem_scan_overlay_range_get
    191  * Purpose:
    192  *   	Retrieve the range of overlay case entries for device specific
    193  *      overlay TCAMs.
    194  * Parameters:
    195  *	unit - unit number.
    196  *      start_index - current index of the table
    197  *      last_index - (OUT) boundary index of the table range
    198  *      overlay - (OUT) current table range is overlay case
    199  * Notes:
    200  *      This is very HW specific.  A future reorganization would
    201  *      put some of this logic in the appropriate chip-specific files.
    202  *      The purpose of this function is to determine if the start_index
    203  *      is in a valid range of the overlay case table, and if so
    204  *      the end of the current boundary.
    205  *      Specifically, this describes the FP_GM_FIELDS table of the
    206  *      Trident-class devices.
    207  * Returns:
    208  *	SOC_E_MEMORY if can't allocate cache.
    209  */
    210 
    211 STATIC int
    212 _soc_mem_scan_overlay_range_get(int unit, int start_index,
    213                                 int *last_index, int *overlay)
    214 {
    215     int slice, low_slices, low_size, high_size, boundary;
    216     fp_port_field_sel_entry_t pfs_entry;
    217     soc_field_t _trx_slice_pairing_field[] = {
    218         SLICE1_0_PAIRINGf,
    219         SLICE3_2_PAIRINGf,
    220         SLICE5_4_PAIRINGf,
    221         SLICE7_6_PAIRINGf,
    222         SLICE9_8_PAIRINGf,
    223         SLICE11_10_PAIRINGf
    224     };
    225 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
    226     if (SOC_IS_TD2P_TT2P(unit)) {
    227         low_slices = SOC_TD2P_IFP_LOW_SLICES;
    228         low_size = SOC_TD2P_IFP_LOW_SLICE_SIZE;
    229         high_size = SOC_TD2P_IFP_HIGH_SLICE_SIZE;
    230     } else 
    231 #endif    
    232 #if defined(BCM_MONTEREY_SUPPORT)
    233     if (SOC_IS_MONTEREY(unit)) {
    234         low_slices = SOC_MONTEREY_IFP_LOW_SLICES;
    235         low_size = SOC_MONTEREY_IFP_LOW_SLICE_SIZE;
    236         high_size = SOC_MONTEREY_IFP_HIGH_SLICE_SIZE;
    237     } else
    238 #endif
    239 #if defined(BCM_APACHE_SUPPORT)
    240     if (SOC_IS_APACHE(unit)) {
    241         low_slices = SOC_APACHE_IFP_LOW_SLICES;
    242         low_size = SOC_APACHE_IFP_LOW_SLICE_SIZE;
    243         high_size = SOC_APACHE_IFP_HIGH_SLICE_SIZE;
    244     } else
    245 #endif
    246     if (SOC_IS_TD2_TT2(unit)) {
    247         low_slices = SOC_TD2_IFP_LOW_SLICES;
    248         low_size = SOC_TD2_IFP_LOW_SLICE_SIZE;
    249         high_size = SOC_TD2_IFP_HIGH_SLICE_SIZE;
    250     } else if (SOC_IS_TD_TT(unit)) {
    251         low_slices = SOC_TD_IFP_LOW_SLICES;
    252         low_size = SOC_TD_IFP_LOW_SLICE_SIZE;
    253         high_size = SOC_TD_IFP_HIGH_SLICE_SIZE;
    254     } else {
    255         /* This is not a valid device for this function. */
    256         return SOC_E_INTERNAL;
    257     }
    258 
    259     /*
    260      * The FP slices are composed of two different slice sizes.
    261      * This logic determines in which slice a given index appears.
    262      * From the defines above, the structure is
    263      * TD/TD+: 4 small slices (low) + 6 large slices (high)
    264      * TD2:    4 large slices (low) + 8 small slices (high)
    265      * The "boundary" is the first index of the high slices segment,
    266      * or (last low slice segment index + 1), to determine in which
    267      * section the provided index lies, high or low.
    268      */
    269     boundary = low_slices * low_size;
    270     if (start_index < boundary) {
    271         slice = start_index / low_size;
    272         *last_index = ((slice +1) * low_size) - 1;
    273     } else {
    274         slice = ((start_index - boundary) / high_size);
    275         *last_index = boundary + ((slice +1) * high_size) - 1;
    276         slice += low_slices;
    277     }
    278 
    279     if (slice % 2) {
    280         /*  FP_PORT_FIELD_SEL entry 0 */
    281         SOC_IF_ERROR_RETURN
    282             (READ_FP_PORT_FIELD_SELm(unit, MEM_BLOCK_ANY, 0, &pfs_entry));
    283         /* coverity[overrun-local] */
    284         if (soc_FP_PORT_FIELD_SELm_field32_get(unit, &pfs_entry,
    285                                    _trx_slice_pairing_field[slice / 2])) {
    286         
    287             *overlay = TRUE;
    288         } else {
    289             *overlay = FALSE;
    290         }
    291     }
    292 
    293     return SOC_E_NONE;       
    294 }
    295 #endif /* BCM_TRIDENT_SUPPORT */
    296 
    297 STATIC void
    298 _soc_mem_scan_info_free(int unit)
    299 {
    300     soc_stat_t *stat = SOC_STAT(unit);
    301     _soc_mem_scan_table_info_t *table_info;
    302     uint32 *last_xy_tcam_p, *last_otb_p;
    303     int            ser_idx;
    304 
    305     if (NULL == scan_info[unit]) {
    306         /* Nothing to do */
    307         return;
    308     }
    309 
    310     if (NULL == scan_info[unit]->table_info) {
    311         sal_free(scan_info[unit]);
    312         return;
    313     }
    314 
    315     last_xy_tcam_p = NULL;
    316     last_otb_p = NULL;
    317     for (ser_idx = 0; ser_idx < scan_info[unit]->num_tables; ser_idx++) {
    318         table_info = &(scan_info[unit]->table_info[ser_idx]);
    319 
    320         /* We can have multiple table entries pointing to the
    321          * same XY TCAM cache when different HW pipes have
    322          * identical info.  Only free the memory once. */
    323         if ((NULL != table_info->xy_tcam_cache) &&
    324             (last_xy_tcam_p != table_info->xy_tcam_cache)){
    325 
    326             stat->mem_cache_count--;
    327             stat->mem_cache_size -=
    328                 WORDS2BYTES(table_info->size * table_info->entry_dw);
    329 #if defined(BCM_TOMAHAWK_SUPPORT)
    330             LOG_VERBOSE(BSL_LS_SOC_SER, (BSL_META_U(unit,
    331                                   "_soc_mem_scan_info_free: freed cache for mem %s, new mem_cache_count = %0d, new mem_cache_size = %0d, ti_xy_tcam_cache = %p, ti_overlay_tcam_bitmap = %p\n"),
    332                        SOC_MEM_NAME(unit, table_info->mem), stat->mem_cache_count,
    333                        stat->mem_cache_size, table_info->xy_tcam_cache,
    334                        table_info->overlay_tcam_bitmap));
    335 #endif
    336 
    337             last_xy_tcam_p = table_info->xy_tcam_cache;
    338             sal_free(table_info->xy_tcam_cache);
    339         }
    340         /* The overlay bitmap is used by all of the memories
    341          * which are HW overlays.  Only free the memory once. */
    342         if ((NULL != table_info->overlay_tcam_bitmap) &&
    343             (last_otb_p != table_info->overlay_tcam_bitmap)){
    344             last_otb_p = table_info->overlay_tcam_bitmap;
    345             sal_free(table_info->overlay_tcam_bitmap);
    346         }
    347 
    348     }
    349 
    350     sal_free(scan_info[unit]->table_info);
    351     sal_free(scan_info[unit]);
    352     scan_info[unit] = NULL;
    353     return;
    354 }
    355 
    356 #ifdef BCM_ESW_SUPPORT
    357 STATIC void
    358 _soc_mem_scan_dynamic_fields_clear(int unit, soc_mem_t mem, uint32 *entry);
    359 #endif /* BCM_ESW_SUPPORT */
    360 
    361 #if defined(BCM_TRIDENT_SUPPORT)
    362 void
    363 soc_mem_scan_mask_get(int unit, soc_mem_t mem, int copyno, int acc_type,
    364                       uint32 *mask, uint32 mask_length)
    365 {
    366 
    367     _soc_mem_scan_table_info_t *table_info = NULL;
    368     uint32    ser_flags = 0;
    369     int       ser_idx;
    370     int       no_dma = FALSE;
    371     int       no_cache;
    372     uint32    *cache = NULL;
    373     uint32    copy_length = 0;
    374 
    375     sal_memset((void *)mask, 0xff, mask_length);
    376 
    377     if (scan_info[unit] == NULL) {
    378         return;
    379     }
    380 
    381     if (SOC_CONTROL(unit)->tdma_enb == 0) { /* not enabled */
    382         no_dma = TRUE;
    383     }
    384 
    385     for (ser_idx = 0; ser_idx < scan_info[unit]->num_tables; ser_idx++) {
    386         table_info = _MEM_SCAN_TABLE_INFO(unit, ser_idx);
    387         ser_flags = table_info->ser_flags;
    388         if (_SOC_MEM_ADDR_ACC_TYPE_PIPE_Y == acc_type) {
    389             if (mem == table_info->mem &&
    390                 (acc_type == (ser_flags & _SOC_SER_FLAG_ACC_TYPE_MASK))) {
    391                 break;
    392             }
    393         } else {
    394             if (mem == table_info->mem) {
    395                 break;
    396             }
    397         }
    398     }
    399     if (ser_idx == scan_info[unit]->num_tables) {
    400         return;
    401     }
    402 
    403     if (!no_dma && (0 != (ser_flags & _SOC_SER_FLAG_SW_COMPARE))) {
    404         no_cache = FALSE;
    405         if (copyno == -1) {
    406             copyno = SOC_MEM_BLOCK_ANY(unit, mem);
    407         }
    408         cache = SOC_MEM_STATE(unit, mem).cache[copyno];
    409         if (NULL == cache) {
    410             no_cache = TRUE;
    411         }
    412         if (no_cache) {
    413             return;
    414         }
    415         copy_length = sizeof(table_info->mask) > mask_length ?
    416                                     mask_length : sizeof(table_info->mask);
    417 
    418         sal_memcpy((void *)mask, (void *)table_info->mask, copy_length);
    419     }
    420 }
    421 #endif
    422 /*
    423  * Function:
    424  * 	_soc_mem_scan_info_init
    425  * Purpose:
    426  *   	Create TCAM memory information structure and 
    427  *      allocate XY TCAM cache used by SW comparison tables.
    428  * Parameters:
    429  *	unit - unit number.
    430  * Returns:
    431  *	SOC_E_MEMORY if can't allocate cache.
    432  */
    433 
    434 STATIC int
    435 _soc_mem_scan_info_init(int unit)
    436 {
    437     int bits, entry_dw, index_cnt;
    438     soc_mem_t      mem;
    439     _soc_ser_parity_info_t *ser_info;
    440     _soc_generic_ser_info_t *gen_ser_info;
    441     _soc_mem_scan_table_info_t *table_info;
    442     int            ser_idx;
    443     uint32         ser_flags;
    444     uint32         ser_dynamic_state;
    445     int generic; /* Booleans */
    446     int alloc_size, idx;
    447     int            no_dma = FALSE;
    448     int blk, no_cache;
    449     uint32 *cache;
    450 #if defined(BCM_TRIDENT_SUPPORT)
    451     soc_mem_t      last_mem = INVALIDm;
    452     int cache_offset, slice_last_idx, rv, overlay;
    453     int overlay_created = FALSE;
    454     uint8 *vmap;
    455     soc_stat_t *stat = SOC_STAT(unit);
    456     soc_pbmp_t pbmp_data, pbmp_mask;
    457 #endif /* BCM_TRIDENT_SUPPORT */
    458     /* Any future non-TCAM init should be put here */
    459     /* TCAM info analysis */
    460     if (NULL == _soc_ser_info_p[unit]) {
    461         return SOC_E_NONE;
    462     }
    463 
    464     /* Clean up any previous state */
    465     _soc_mem_scan_info_free(unit);
    466 
    467     ser_idx = 0;
    468     generic = _soc_ser_info_is_generic[unit];
    469 
    470     if (generic) {
    471         gen_ser_info = (_soc_generic_ser_info_t *)_soc_ser_info_p[unit];
    472         ser_info = NULL;
    473     } else {
    474         ser_info = (_soc_ser_parity_info_t *)_soc_ser_info_p[unit];
    475         gen_ser_info = NULL;
    476     }
    477 
    478     while (generic ? (NULL != gen_ser_info) : (NULL != ser_info)) {
    479         if (generic) {
    480             mem = gen_ser_info[ser_idx].mem;
    481         } else {
    482             mem = ser_info[ser_idx].mem;
    483         }
    484 
    485         if (INVALIDm == mem) {
    486             break;
    487         }
    488 
    489         if (!SOC_MEM_IS_VALID(unit, mem)
    490 #if defined(BCM_TOMAHAWK_SUPPORT)
    491             && (!SOC_IS_TOMAHAWKX(unit)) /* mem can be invalid in some latency_modes */
    492 #endif
    493            ) {
    494             LOG_WARN(BSL_LS_SOC_COMMON,
    495                      (BSL_META_U(unit,
    496                                  "SER Scan mem %d invalid at index %d\n"),
    497                       mem, ser_idx));
    498             return SOC_E_INTERNAL;
    499         }
    500         ser_idx++;
    501     }
    502 
    503     if (0 == ser_idx) {
    504         /* No TCAMs to track */
    505         return SOC_E_NONE;
    506     }
    507 
    508     if (SOC_CONTROL(unit)->tdma_enb == 0) { /* not enabled */
    509         no_dma = TRUE;
    510     }
    511 
    512     alloc_size = sizeof(_soc_mem_scan_info_t);
    513     if ((scan_info[unit] = sal_alloc(alloc_size, "memscan info")) == NULL) {
    514         return SOC_E_MEMORY;
    515     }
    516     _MEM_SCAN_INIT_FLAG_SET(unit, SCAN_INFO_NOT_INITIALIZED);
    517 
    518     scan_info[unit]->num_tables = ser_idx;
    519 
    520     alloc_size = ser_idx * sizeof(_soc_mem_scan_table_info_t);
    521     if ((scan_info[unit]->table_info =
    522          sal_alloc(alloc_size, "memscan table info")) == NULL) {
    523         sal_free(scan_info[unit]);
    524         return SOC_E_MEMORY;
    525     }
    526     sal_memset(scan_info[unit]->table_info, 0, alloc_size);
    527 
    528     for (ser_idx = 0; ser_idx < scan_info[unit]->num_tables; ser_idx++) {
    529         table_info = _MEM_SCAN_TABLE_INFO(unit, ser_idx);
    530         if (generic) {
    531             mem = gen_ser_info[ser_idx].mem;
    532             ser_flags = gen_ser_info[ser_idx].ser_flags;
    533             ser_dynamic_state = gen_ser_info[ser_idx].ser_dynamic_state;
    534             bits = 0;
    535             for (idx = 0; idx < SOC_NUM_GENERIC_PROT_SECTIONS; idx++) {
    536                 if (gen_ser_info[ser_idx].start_end_bits[idx].start_bit != -1) {
    537                     if (bits <
    538                         gen_ser_info[ser_idx].start_end_bits[idx].end_bit) {
    539                         bits =
    540                             gen_ser_info[ser_idx].start_end_bits[idx].end_bit;
    541                     }
    542                 }
    543             }
    544         } else {
    545             mem = ser_info[ser_idx].mem;
    546             ser_flags = ser_info[ser_idx].ser_flags;
    547             ser_dynamic_state = 0;
    548             bits = ser_info[ser_idx].bit_offset;
    549         }
    550 
    551         table_info->mem = mem;
    552         table_info->ser_flags = ser_flags;
    553         table_info->ser_dynamic_state = ser_dynamic_state;
    554  
    555         entry_dw = soc_mem_entry_words(unit, mem);
    556         index_cnt = soc_mem_index_count(unit, mem);
    557         table_info->index_min = soc_mem_index_min(unit, mem);
    558         table_info->index_max = soc_mem_index_max(unit, mem);
    559         table_info->entry_dw = entry_dw;
    560         table_info->size = index_cnt;
    561 
    562         if (no_dma) {
    563             if (0 != (ser_flags & _SOC_SER_FLAG_SW_COMPARE)) {
    564                 /* Must use DMA implmementation for SW protected tables,
    565                  * disable this table for memory scan */
    566                 table_info->index_min = 0;
    567                 table_info->index_max = -1;
    568                 table_info->size = 0;
    569                 continue;
    570             } else {
    571                 /* DMA is not enabled, use PIO access for this table */
    572                 table_info->ser_flags |= _SOC_SER_FLAG_NO_DMA;
    573             }
    574         }
    575 
    576         if (0 != (ser_flags & _SOC_SER_FLAG_SW_COMPARE)) {
    577             no_cache = FALSE;
    578             SOC_MEM_BLOCK_ITER(unit, mem, blk) {
    579                 cache = SOC_MEM_STATE(unit, mem).cache[blk];
    580                 if (NULL == cache) {
    581                     no_cache = TRUE;
    582                 }
    583             }
    584             if (no_cache) {
    585                 /* Caching is disabled for this memory.
    586                  * We cannot do SW comparison, so skip the setup.
    587                  * Disable mem scan on this table.
    588                  */
    589                 table_info->index_min = 0;
    590                 table_info->index_max = -1;
    591                 table_info->size = 0;
    592                 continue;
    593             }
    594 
    595             _soc_mem_scan_ser_tcam_datamask_get(entry_dw, bits,
    596                                                 table_info->mask);
    597 #ifdef BCM_ESW_SUPPORT                                                
    598             if ((SOC_MEM_INFO(unit, mem).flags & SOC_MEM_FLAG_DYNAMIC)) {
    599                 _soc_mem_scan_dynamic_fields_clear(unit, mem, table_info->mask);
    600             }                                    
    601 #endif /* BCM_ESW_SUPPORT */
    602 
    603             if (0 == (ser_flags & _SOC_SER_FLAG_XY_READ)) {
    604                 continue;
    605             }
    606 
    607 #if defined(BCM_TRIDENT_SUPPORT)
    608             if (SOC_IS_TD_TT(unit) &&
    609                 (mem == FP_GLOBAL_MASK_TCAMm)) {
    610                 soc_mem_pbmp_field_get(unit, mem, table_info->mask,
    611                                        IPBMf, &pbmp_data);
    612                 soc_mem_pbmp_field_get(unit, mem, table_info->mask,
    613                                        IPBM_MASKf, &pbmp_mask);
    614                 if (0 == (ser_flags & _SOC_SER_FLAG_ACC_TYPE_MASK)) {
    615                     SOC_PBMP_AND(pbmp_data, PBMP_XPIPE(unit));
    616                     SOC_PBMP_AND(pbmp_mask, PBMP_XPIPE(unit));
    617                 } else {
    618                     SOC_PBMP_AND(pbmp_data, PBMP_YPIPE(unit));
    619                     SOC_PBMP_AND(pbmp_mask, PBMP_YPIPE(unit));
    620                 }
    621                 soc_mem_pbmp_field_set(unit, mem, table_info->mask,
    622                                        IPBMf, &pbmp_data);
    623                 soc_mem_pbmp_field_set(unit, mem, table_info->mask,
    624                                        IPBM_MASKf, &pbmp_mask);
    625             }
    626 
    627             _soc_mem_tcam_dm_to_xy(unit, mem, 1,
    628                                    soc_mem_entry_null(unit, mem),
    629                                    table_info->null_entry,
    630                                    NULL);
    631             
    632             /* Need the XY tcam cache */
    633             if (last_mem == mem) {
    634                 /* Same memory but different pipes,
    635                  * copy the previous info */
    636                 table_info->xy_tcam_cache =
    637                     _MEM_SCAN_TABLE_INFO(unit, ser_idx - 1)->xy_tcam_cache;
    638                 if ((0 != (ser_flags & _SOC_SER_FLAG_OVERLAY)) &&
    639                     overlay_created) {
    640                     table_info->overlay_tcam_bitmap =
    641                         _MEM_SCAN_TABLE_INFO(unit, ser_idx - 1)->overlay_tcam_bitmap;
    642                 }
    643             } else {
    644                 /* Time to create the XY cache */
    645                 alloc_size = WORDS2BYTES(index_cnt * entry_dw);
    646                 if ((table_info->xy_tcam_cache =
    647                      sal_alloc(alloc_size,
    648                                "memscan XY TCAM info")) == NULL) {
    649                     _soc_mem_scan_info_free(unit);
    650                     return SOC_E_MEMORY;
    651                 }
    652                 sal_memset(table_info->xy_tcam_cache, 0, alloc_size);
    653                 stat->mem_cache_count++;
    654                 stat->mem_cache_size += alloc_size;
    655                 LOG_VERBOSE(BSL_LS_SOC_SER, (BSL_META_U(unit,
    656                                       "_soc_mem_scan_info_init: added cache for mem %s, new mem_cache_count = %0d, new mem_cache_size = %0d, ti_xy_tcam_cache = %p\n"),
    657                            SOC_MEM_NAME(unit, table_info->mem), stat->mem_cache_count,
    658                            stat->mem_cache_size, table_info->xy_tcam_cache));
    659 
    660                 if (0 != (ser_flags & _SOC_SER_FLAG_OVERLAY)) {
    661                     if (overlay_created) {
    662                         table_info->overlay_tcam_bitmap =
    663                             _MEM_SCAN_TABLE_INFO(unit, ser_idx - 1)->overlay_tcam_bitmap;
    664                     } else {
    665                         alloc_size = SHR_BITALLOCSIZE(index_cnt);
    666                         if ((table_info->overlay_tcam_bitmap =
    667                              sal_alloc(alloc_size,
    668                                  "memscan overlay TCAM info")) == NULL) {
    669                             _soc_mem_scan_info_free(unit);
    670                             return SOC_E_MEMORY;
    671                         }
    672                         sal_memset(table_info->overlay_tcam_bitmap, 0,
    673                                    alloc_size);
    674                         overlay_created = TRUE;
    675                     }
    676                 }
    677                 /* Copy the current state of the cache */
    678                 SOC_MEM_BLOCK_ITER(unit, mem, blk) {
    679                     cache = SOC_MEM_STATE(unit, mem).cache[blk];
    680                     vmap = SOC_MEM_STATE(unit, mem).vmap[blk];
    681                     if ((0 != (ser_flags & _SOC_SER_FLAG_OVERLAY)) &&
    682                         (0 != (ser_flags & _SOC_SER_FLAG_OVERLAY_CASE))) {
    683                         slice_last_idx = -1;
    684                     } else {
    685                         /* For any non-overlay table, skip all of the
    686                          * complex logic in the loop below.  Just
    687                          * convert the DM cache to XY. */
    688                         slice_last_idx = table_info->index_max;
    689                     }
    690                     overlay = FALSE;
    691                     for (idx = table_info->index_min;
    692                          idx <= table_info->index_max;
    693                          idx++) {
    694 			if (!CACHE_VMAP_TST(vmap, idx)) {
    695 			    continue;
    696 			}
    697                         if (idx > slice_last_idx) {
    698                             /* We must be the overlay table, in a new slice.
    699                              * Get the new the slice index limit, and
    700                              * check if this range is overlay view. */
    701                             rv = _soc_mem_scan_overlay_range_get(unit, idx,
    702                                                &slice_last_idx, &overlay);
    703                             if (SOC_FAILURE(rv)) {
    704                                 _soc_mem_scan_info_free(unit);
    705                                 return rv;
    706                             }
    707                         }
    708                         cache_offset = idx * entry_dw;
    709                         /* Is this a valid overlay entry? Note that. */
    710                         if (overlay &&
    711                             (soc_FP_GM_FIELDSm_field32_get(unit,
    712                                        cache + cache_offset, VALIDf))) {
    713                             SHR_BITSET(table_info->overlay_tcam_bitmap, idx);
    714                         }
    715                         /* Synchronized entry available,
    716                          * convert if necessary */
    717                         _soc_mem_tcam_dm_to_xy(unit, mem, 1,
    718                                                cache + cache_offset,
    719                                  table_info->xy_tcam_cache + cache_offset,
    720                                                NULL);
    721                     }
    722                 }
    723             }
    724 #endif /* BCM_TRIDENT_SUPPORT */
    725         }
    726 #if defined(BCM_TRIDENT_SUPPORT)        
    727         last_mem = mem;
    728 #endif /* BCM_TRIDENT_SUPPORT */
    729     }
    730     _MEM_SCAN_INIT_FLAG_SET(unit, SCAN_INFO_INITIALIZED);
    731 
    732     return SOC_E_NONE;
    733 }
    734 
    735 void
    736 soc_mem_scan_tcam_cache_update(int unit, soc_mem_t mem,
    737                                int index_begin, int index_end,
    738                                uint32 *xy_entries)
    739 {
    740     int            ser_idx, num_tables, entry_dw, num_entries;
    741     uint32         ser_flags;
    742     uint32         *cache;
    743     _soc_mem_scan_table_info_t *table_info = NULL;
    744     SHR_BITDCL     *overlay_bitmap;
    745     int            effective_begin = (index_begin < index_end) ? index_begin : index_end;
    746     int            effective_end = (index_begin < index_end) ? index_end : index_begin;
    747 
    748     if (NULL == scan_info[unit] ||
    749         SCAN_INFO_NOT_INITIALIZED == _MEM_SCAN_INIT_FLAG_GET(unit)) {
    750         /* Not yet initialized */
    751         if (NULL != scan_info[unit] &&
    752             SCAN_INFO_NOT_INITIALIZED == _MEM_SCAN_INIT_FLAG_GET(unit)) {
    753             LOG_VERBOSE(BSL_LS_SOC_SER, (BSL_META_U(unit,
    754                                   "scan_info initialization is not completed\n")));
    755         }
    756         return;
    757     }
    758 
    759     num_tables = scan_info[unit]->num_tables;
    760     for (ser_idx = 0; ser_idx < num_tables; ser_idx++) {
    761         table_info = _MEM_SCAN_TABLE_INFO(unit, ser_idx);
    762         if (mem == table_info->mem) {
    763             break;
    764         }
    765     }
    766 
    767     if ((ser_idx == num_tables) || (0 == table_info->size) ||
    768         (0 == (table_info->ser_flags &_SOC_SER_FLAG_SW_COMPARE))) {
    769         /* Nothing to do */
    770         return;
    771     }
    772 
    773     ser_flags = table_info->ser_flags;
    774     entry_dw = table_info->entry_dw;
    775     cache = table_info->xy_tcam_cache;
    776     overlay_bitmap = table_info->overlay_tcam_bitmap;
    777     num_entries = effective_end - effective_begin + 1;
    778 
    779     sal_memcpy(cache + (effective_begin * entry_dw), xy_entries,
    780                WORDS2BYTES(num_entries * entry_dw));
    781 
    782     if (0 != (ser_flags & _SOC_SER_FLAG_OVERLAY)) {
    783         /* Record last overlay table view to write to HW */
    784         if (0 != (ser_flags & _SOC_SER_FLAG_OVERLAY_CASE)) {
    785             SHR_BITSET_RANGE(overlay_bitmap, effective_begin, num_entries);
    786         } else {
    787             SHR_BITCLR_RANGE(overlay_bitmap, effective_begin, num_entries);
    788         }
    789     }
    790 }
    791 
    792 
    793 /*
    794  * Function:
    795  * 	soc_mem_scan_running
    796  * Purpose:
    797  *   	Boolean to indicate if the memory scan thread is running
    798  * Parameters:
    799  *	unit - unit number.
    800  *	rate - (OUT) if non-NULL, number of entries scanned per interval
    801  *	interval - (OUT) if non-NULL, receives current wake-up interval.
    802  */
    803 
    804 int
    805 soc_mem_scan_running(int unit, int *rate, sal_usecs_t *interval)
    806 {
    807     soc_control_t	*soc = SOC_CONTROL(unit);
    808 
    809     if (soc->mem_scan_pid  != SAL_THREAD_ERROR) {
    810         if (rate != NULL) {
    811             *rate = soc->mem_scan_rate;
    812         }
    813 
    814         if (interval != NULL) {
    815             *interval = soc->mem_scan_interval;
    816         }
    817     }
    818 
    819     return (soc->mem_scan_pid != SAL_THREAD_ERROR);
    820 }
    821 
    822 /*
    823  * Function:
    824  * 	soc_mem_scan_start
    825  * Purpose:
    826  *   	Start memory scan thread
    827  * Parameters:
    828  *	unit - unit number.
    829  *	rate - maximum number of entries to scan each time thread runs
    830  *	interval - how often the thread should run (microseconds).
    831  * Returns:
    832  *	SOC_E_MEMORY if can't create thread.
    833  */
    834 
    835 int
    836 soc_mem_scan_start(int unit, int rate, sal_usecs_t interval)
    837 {
    838     soc_control_t *soc = SOC_CONTROL(unit);
    839     int pri;
    840     int rv = SOC_E_NONE;
    841 
    842     if (soc->mem_scan_lock == NULL) {
    843         return SOC_E_INIT;
    844     }
    845 
    846     if (rate <= 0) {
    847         return (SOC_E_PARAM);
    848     }
    849 
    850     SOC_MEM_SCAN_LOCK(unit);
    851 
    852     if (soc->mem_scan_pid != SAL_THREAD_ERROR) {
    853         rv= soc_mem_scan_stop(unit);
    854         if (SOC_FAILURE(rv)) {
    855             SOC_MEM_SCAN_UNLOCK(unit);
    856             return rv;
    857         }
    858     }
    859 
    860     sal_snprintf(soc->mem_scan_name, sizeof (soc->mem_scan_name),
    861                  "bcmMEM_SCAN.%d", unit);
    862 
    863     soc->mem_scan_rate = rate;
    864     soc->mem_scan_interval = interval;
    865 
    866     if (interval == 0) {
    867         SOC_MEM_SCAN_UNLOCK(unit);
    868         return SOC_E_NONE;
    869     }
    870 
    871     if (soc->mem_scan_pid == SAL_THREAD_ERROR) {
    872         pri = soc_property_get(unit, spn_MEM_SCAN_THREAD_PRI, 50);
    873         soc->mem_scan_pid = sal_thread_create(soc->mem_scan_name,
    874                                               SAL_THREAD_STKSZ,
    875                                               pri,
    876                                               _soc_mem_scan_thread,
    877                                               INT_TO_PTR(unit));
    878 
    879         if (soc->mem_scan_pid == SAL_THREAD_ERROR) {
    880             LOG_ERROR(BSL_LS_SOC_COMMON,
    881                           (BSL_META_U(unit,
    882                                       "soc_mem_scan_start:"
    883                                       "Could not start mem_scan thread\n")));
    884             SOC_MEM_SCAN_UNLOCK(unit);
    885             return SOC_E_MEMORY;
    886         }
    887     }
    888 
    889 #if defined(BCM_XGS_SUPPORT)
    890     if (soc_feature(unit, soc_feature_tcam_scan_engine)) {
    891         (void) soc_ser_tcam_scan_engine_enable(unit, TRUE);
    892     }
    893 #endif
    894 
    895     SOC_MEM_SCAN_UNLOCK(unit);
    896     return SOC_E_NONE;
    897 }
    898 
    899 /*
    900  * Function:
    901  * 	soc_mem_scan_stop
    902  * Purpose:
    903  *   	Stop memory scan thread
    904  * Parameters:
    905  *	unit - unit number.
    906  * Returns:
    907  *	SOC_E_XXX
    908  */
    909 
    910 int
    911 soc_mem_scan_stop(int unit)
    912 {
    913     soc_control_t *soc = SOC_CONTROL(unit);
    914     int rv = SOC_E_NONE;
    915     soc_timeout_t to;
    916     int tosec;
    917 
    918     if (soc->mem_scan_lock == NULL) {
    919         return SOC_E_INIT;
    920     }
    921 
    922     SOC_MEM_SCAN_LOCK(unit);
    923 
    924     /* Request exit */
    925     soc->mem_scan_interval = 0;
    926 
    927     if (soc->mem_scan_pid != SAL_THREAD_ERROR) {
    928         /* Wake up thread so it will check the exit flag */
    929         sal_sem_give(soc->mem_scan_notify);
    930 
    931         /* Give thread a few seconds to wake up and exit */
    932         tosec = 5;
    933 #ifdef PLISIM
    934         if (SAL_BOOT_PLISIM) {
    935             tosec = 15;
    936         }
    937 #endif
    938         soc_timeout_init(&to, tosec * 1000000, 0);
    939 
    940         while (soc->mem_scan_pid != SAL_THREAD_ERROR) {
    941             if (soc_timeout_check(&to)) {
    942                 LOG_ERROR(BSL_LS_SOC_COMMON,
    943                           (BSL_META_U(unit,
    944                                       "soc_mem_scan_stop: thread will not exit\n")));
    945                 rv = SOC_E_INTERNAL;
    946                 break;
    947             }
    948         }
    949     }
    950 
    951     /* Ensure memscan has exited */
    952     if (soc->mem_scan_pid == SAL_THREAD_ERROR) {
    953         _soc_mem_scan_info_free(unit);
    954     }
    955 
    956 
    957 #if defined(BCM_XGS_SUPPORT)
    958     if (soc_feature(unit, soc_feature_tcam_scan_engine)) {
    959         (void) soc_ser_tcam_scan_engine_enable(unit, FALSE);
    960     }
    961 #endif
    962 
    963     SOC_MEM_SCAN_UNLOCK(unit);
    964     return rv;
    965 }
    966 
    967 #if defined(BCM_TRIDENT_SUPPORT)
    968 #define SOC_MEM_SCAN_READ_LOCK(_unit_, _mem_, _ser_flags_)      \
    969             if (0 != (_ser_flags_ & _SOC_SER_FLAG_OVERLAY)) {   \
    970                  IP_ARBITER_LOCK(_unit_); \
    971                  MEM_LOCK(_unit_, FP_GLOBAL_MASK_TCAMm);        \
    972                  MEM_LOCK(_unit_, FP_GM_FIELDSm);               \
    973             } else MEM_LOCK(_unit_, _mem_)
    974         
    975 #define SOC_MEM_SCAN_READ_UNLOCK(_unit_, _mem_, _ser_flags_)    \
    976             if (0 != (_ser_flags_ & _SOC_SER_FLAG_OVERLAY)) {   \
    977                  MEM_UNLOCK(_unit_, FP_GM_FIELDSm);             \
    978                  MEM_UNLOCK(_unit_, FP_GLOBAL_MASK_TCAMm);      \
    979                  IP_ARBITER_UNLOCK(_unit_); \
    980             } else MEM_UNLOCK(_unit_, _mem_)
    981 #else
    982 #define SOC_MEM_SCAN_READ_LOCK(_unit_, _mem_, _ser_flags_)      \
    983             MEM_LOCK(_unit_, _mem_)
    984         
    985 #define SOC_MEM_SCAN_READ_UNLOCK(_unit_, _mem_, _ser_flags_)    \
    986             MEM_UNLOCK(_unit_, _mem_)
    987 
    988 #endif
    989 
    990 STATIC int
    991 _soc_memscan_ifp_slice_adjust(int unit, _soc_mem_scan_table_info_t *table_info,
    992                               int *idx, int *idx_count)
    993 {
    994    int memscan_slice_size;
    995    int memscan_slice_type;
    996    int cur_slice_num, end_slice_num;
    997    int cfg_cur_slice_type, cfg_end_slice_type;
    998    int cfg_cur_slice_enabled, cfg_end_slice_enabled;
    999    int pipe;
   1000    int rv;
   1001  
   1002    /* unit specific constants */
   1003    int narrow_slice_size;
   1004    int narrow_slice_type;
   1005    int wide_slice_type;
   1006    soc_mem_t ifp_tcam_narrow_view = INVALIDm;
   1007    soc_mem_t ifp_tcam_wide_view = INVALIDm;
   1008 #ifdef BCM_TRIDENT3_SUPPORT
   1009    soc_mem_t ifp_tcam_wide_pipe_view[] = {
   1010        IFP_TCAM_WIDE_PIPE0m,
   1011        IFP_TCAM_WIDE_PIPE1m
   1012    };
   1013    int slice_skip = 0;
   1014 #endif
   1015    int (*soc_ifp_slice_mode_get)(int, int, int, int*, int*) = NULL;
   1016 
   1017    if ((table_info == NULL) || (idx == NULL) || (idx_count == NULL)) {
   1018        return SOC_E_PARAM;
   1019    }
   1020 
   1021    /* default - good for TH - use 'unit' to override */
   1022    narrow_slice_size = 512;
   1023    narrow_slice_type = 0;
   1024    wide_slice_type = 1;
   1025 #if defined(BCM_TOMAHAWK_SUPPORT)
   1026    if (SOC_IS_TOMAHAWKX(unit)) {
   1027       ifp_tcam_narrow_view = IFP_TCAMm;
   1028       ifp_tcam_wide_view = IFP_TCAM_WIDEm;
   1029       soc_ifp_slice_mode_get = soc_th_ifp_slice_mode_hw_get;
   1030    }
   1031 #endif /* BCM_TOMAHAWK_SUPPORT */
   1032 #if defined(BCM_TRIDENT3_SUPPORT)
   1033     if (SOC_IS_TRIDENT3X(unit)) {
   1034       narrow_slice_size = 1536;
   1035       ifp_tcam_narrow_view = IFP_TCAMm;
   1036       ifp_tcam_wide_view = IFP_TCAM_WIDEm;
   1037       soc_ifp_slice_mode_get = soc_trident3_ifp_slice_mode_hw_get;
   1038     }
   1039 #endif
   1040    if ((soc_ifp_slice_mode_get == NULL) ||
   1041        (ifp_tcam_narrow_view == INVALIDm) ||
   1042        (ifp_tcam_wide_view == INVALIDm)) {
   1043        return SOC_E_FAIL;
   1044    }
   1045 
   1046    /* When scanning IFP_TCAMm, memscan assumes all slices are Narrow - but only
   1047     * IFP knows the current usage. So, before initiating DMA for IFP_TCAMm view,
   1048     * we must check the state of slice with IFP.
   1049     * Similarly when scanning IFP_TCAM_WIDEm, memscan assumes all slices are
   1050     * Wide - and we must check state of slice with IFP before issuing DMA for
   1051     * IFP_TCAM_WIDEm view
   1052     */
   1053    if (table_info->mem == ifp_tcam_narrow_view) {
   1054        /* currently scanning narrow view */
   1055        memscan_slice_size = narrow_slice_size;
   1056        memscan_slice_type = narrow_slice_type;
   1057    } else if (table_info->mem == ifp_tcam_wide_view) {
   1058        /* currently scanning wide view */
   1059        memscan_slice_size = narrow_slice_size/2;
   1060        memscan_slice_type = wide_slice_type;
   1061    } else {
   1062        return SOC_E_NONE;
   1063    }
   1064 
   1065    if ((table_info->ser_dynamic_state & _SOC_SER_STATE_PIPE_MODE_UNIQUE) &&
   1066        soc_feature(unit, soc_feature_unique_acc_type_access)) {
   1067        pipe = (table_info->ser_flags & _SOC_SER_FLAG_ACC_TYPE_MASK);
   1068    } else {
   1069        pipe = -1;
   1070    }
   1071 
   1072    cur_slice_num = (*idx)/memscan_slice_size;
   1073 #ifdef BCM_TRIDENT3_SUPPORT
   1074    if (SOC_IS_TRIDENT3X(unit) && table_info->mem == IFP_TCAM_WIDEm) {
   1075        soc_td3_ifp_slice_mode_check(unit, ((pipe == -1) ? IFP_TCAM_WIDEm :
   1076                                     ifp_tcam_wide_pipe_view[pipe]),
   1077                                    cur_slice_num, &slice_skip);
   1078        if (slice_skip) {
   1079            *idx = (cur_slice_num + 1) * memscan_slice_size; /* 1st entry of next slice */
   1080            *idx_count = 0; /* Needed for proper accounting of 'entries_interval',
   1081                               to skip the reads for this slice, and also
   1082                               it will get added to idx and then used as
   1083                               start idx value for next iteration in for loop */
   1084            return SOC_E_NONE;
   1085        }
   1086    } else
   1087 #endif
   1088    {
   1089        rv = (soc_ifp_slice_mode_get(unit, pipe, cur_slice_num, &cfg_cur_slice_type,
   1090                                    &cfg_cur_slice_enabled));
   1091        if (SOC_FAILURE(rv) && (rv != SOC_E_CONFIG)) {
   1092            return rv;
   1093        }
   1094 
   1095        if ((memscan_slice_type != cfg_cur_slice_type) || !cfg_cur_slice_enabled ||
   1096            (rv == SOC_E_CONFIG)) {
   1097            *idx = (cur_slice_num + 1) * memscan_slice_size; /* 1st entry of next slice */
   1098            *idx_count = 0; /* Needed for proper accounting of 'entries_interval',
   1099                               to skip the reads for this slice, and also
   1100                               it will get added to idx and then used as
   1101                               start idx value for next iteration in for loop */
   1102            return SOC_E_NONE;
   1103        }
   1104    }
   1105 
   1106    /* Max idx_count by default is equal to chunk_size (256)
   1107     * Here we further limit idx_count to not exceed slice_size.
   1108     * This is not such a big limitation because typically,
   1109     *       slice_size will always be >= chunk_size (256)
   1110     * For chunk_size = 256, there is no new limilation.
   1111     * But if we increase chunk_size to say 512, 1024 then we will limit
   1112     * idx_count to slice_size (which could be 256 or 512) and this is
   1113     * still not a problem - we are still doing DMAs of 256 or 512.
   1114     *
   1115     * Reason for limiting idx_count to not exceed slice_size:
   1116     * such restriction will eliminate the complexity (of having to check
   1117     * slice_type * for all intermediate slices) by avoiding cases where
   1118     * range of entries to be DMA'd can span across more than 2 slices.
   1119     * Thus when end_slice_num != cur_slice_num, we can say end_slice_num =
   1120     * cur_slice_num + 1, if we add restriction that (idx_count <= slice_size)
   1121     */
   1122    if (*idx_count > memscan_slice_size) {
   1123        *idx_count = memscan_slice_size;
   1124    }
   1125 
   1126    end_slice_num = (*idx + *idx_count - 1) / memscan_slice_size;
   1127                                     /* numerator = last_entry to be scanned */
   1128    if (end_slice_num != cur_slice_num) {
   1129        rv = (soc_ifp_slice_mode_get(unit, pipe, end_slice_num,
   1130                                    &cfg_end_slice_type,
   1131                                    &cfg_end_slice_enabled));
   1132        if (SOC_FAILURE(rv) && (rv != SOC_E_CONFIG)) {
   1133           return rv;
   1134        }
   1135        if ((memscan_slice_type != cfg_end_slice_type) || !cfg_end_slice_enabled
   1136             || (rv == SOC_E_CONFIG)) {
   1137            /* Reduce the range to scan up to last entry in cur_slice */
   1138            *idx_count = ((cur_slice_num + 1) * memscan_slice_size) - *idx;
   1139            /* 1st term on RHS = idx of 1st entry in next slice */
   1140        }
   1141    }
   1142    return SOC_E_NONE;
   1143 }
   1144 
   1145 /*
   1146  * Function:
   1147  *     _soc_mem_scan_ser_read_ranges
   1148  * Purpose:
   1149  *       Perform TCAM SER engine protected tables ranged reads,
   1150  *       or SW comparison of non-HW protected tables
   1151  * Parameters:
   1152  *    unit_vp - StrataSwitch unit # (as a void *).
   1153  * Returns:
   1154  *    SOC_E_XXX
   1155  * Notes:
   1156  */
   1157 
   1158 STATIC int
   1159 _soc_mem_scan_ser_read_ranges(int unit, int chunk_size, uint32 *read_buf)
   1160 {
   1161     soc_control_t  *soc = SOC_CONTROL(unit);
   1162     int            rv = SOC_E_NONE;
   1163     int            interval;
   1164     int            entries_interval;
   1165     int            entries_pass, scan_iter = 0;
   1166     soc_mem_t      mem;
   1167     int            entry_dw;
   1168     int            blk;
   1169     int            idx, idx_count, test_count, i, dw;
   1170     uint32         *cache;
   1171     uint32         *null_entry;
   1172     uint32         *mask;
   1173     uint32         *cmp_entry, *hw_entry;
   1174     uint8          *vmap;
   1175     SHR_BITDCL     *overlay_bitmap;
   1176     _soc_mem_scan_table_info_t *table_info;
   1177     int            ser_idx, num_tables;
   1178     uint32         ser_flags;
   1179 #if defined(SOC_UNIQUE_ACC_TYPE_ACCESS)
   1180     uint32         ser_dynamic_state;
   1181 #endif /* SOC_UNIQUE_ACC_TYPE_ACCESS */
   1182 #ifdef BCM_ESW_SUPPORT
   1183     char errstr[80 + SOC_MAX_MEM_WORDS * 9];
   1184     uint8          at;
   1185     uint32         error_index, err_addr;
   1186     _soc_ser_correct_info_t spci;
   1187     soc_stat_t     *stat = SOC_STAT(unit);
   1188 #endif /* BCM_ESW_SUPPORT */
   1189 
   1190     if (NULL == _soc_ser_info_p[unit]) {
   1191         return SOC_E_NONE;
   1192     }
   1193 
   1194     entries_interval = 0;
   1195     entries_pass = 0;
   1196 
   1197     if (NULL == scan_info[unit]) {
   1198        /* Not yet initialized, but SER info was checked above,
   1199         * so do init now.  */
   1200         SOC_IF_ERROR_RETURN(_soc_mem_scan_info_init(unit));
   1201     }
   1202 
   1203     num_tables = scan_info[unit]->num_tables;
   1204 
   1205     cache = NULL;
   1206     null_entry = NULL;
   1207     mask = NULL;
   1208     vmap = NULL;
   1209     overlay_bitmap = NULL;
   1210 
   1211     for (ser_idx = 0; ser_idx < num_tables; ser_idx++) {
   1212         if (soc->mem_scan_interval == 0) {
   1213             break;
   1214         }
   1215         table_info = _MEM_SCAN_TABLE_INFO(unit, ser_idx);
   1216         mem = table_info->mem;
   1217 #ifdef INCLUDE_XFLOW_MACSEC
   1218         if (mem == ISEC_SC_TCAMm || mem == ISEC_SP_TCAMm) {
   1219             if (!soc_feature(unit, soc_feature_xflow_macsec)) {
   1220                 continue;
   1221             }
   1222         }
   1223 #endif
   1224         if (0 == table_info->size) {
   1225             /* This configuration doesn't use the memory, skip */
   1226             continue;
   1227         }
   1228         ser_flags = table_info->ser_flags;
   1229         entry_dw = table_info->entry_dw;
   1230 
   1231         if (0 != (ser_flags & _SOC_SER_FLAG_VIEW_DISABLE)) {
   1232             /* This entry was intended only for ser_engine configuration.
   1233              * Skip memscan for this entry */
   1234             continue;
   1235         }
   1236 
   1237         if (SOC_MEM_INFO(unit, mem).flags & 
   1238             SOC_MEM_FLAG_SER_PARITY_ENABLE_SKIP) {
   1239             /* Parity checking is not enabled explictly.
   1240              * Skip memscan for this entry */
   1241             continue;
   1242         }
   1243 #if defined(SOC_UNIQUE_ACC_TYPE_ACCESS)
   1244         ser_dynamic_state = table_info->ser_dynamic_state;
   1245         if ((ser_dynamic_state & _SOC_SER_STATE_PIPE_MODE_UNIQUE) &&
   1246             soc_feature(unit, soc_feature_unique_acc_type_access)) {
   1247                 at = (ser_flags & _SOC_SER_FLAG_ACC_TYPE_MASK);
   1248                 if (SOC_MEM_UNIQUE_ACC(unit, mem) != NULL) {
   1249                     mem = SOC_MEM_UNIQUE_ACC(unit, mem)[at];
   1250                 }
   1251         }
   1252 #endif /* SOC_UNIQUE_ACC_TYPE_ACCESS */
   1253 
   1254         SOC_MEM_BLOCK_ITER(unit, mem, blk) {
   1255             if (soc->mem_scan_interval == 0) {
   1256                 break;
   1257             }
   1258 
   1259             if (0 != (ser_flags & _SOC_SER_FLAG_SW_COMPARE)) {
   1260                 if (soc_feature(unit, soc_feature_xy_tcam)) {
   1261                     cache = table_info->xy_tcam_cache;
   1262                 } else {
   1263                     cache = SOC_MEM_STATE(unit, mem).cache[blk];
   1264                 }
   1265                 vmap = SOC_MEM_STATE(unit, mem).vmap[blk];
   1266                 null_entry = table_info->null_entry;
   1267                 mask = table_info->mask;
   1268                 overlay_bitmap = table_info->overlay_tcam_bitmap;
   1269             }
   1270             
   1271             if (0 != (ser_flags & _SOC_SER_FLAG_SIZE_VERIFY)) {
   1272                  table_info->index_min = soc_mem_index_min(unit, mem);
   1273                  table_info->index_max = soc_mem_index_max(unit, mem);
   1274             }
   1275 
   1276             for (idx = table_info->index_min;
   1277                  idx <= table_info->index_max;
   1278                  idx += idx_count) {
   1279                 if (soc->mem_scan_interval == 0) {
   1280                     break;
   1281                 }
   1282 
   1283                 idx_count = table_info->index_max - idx + 1;
   1284 
   1285                 if (idx_count > chunk_size) {
   1286                     idx_count = chunk_size;
   1287                 }
   1288 
   1289                 if (entries_interval + idx_count > soc->mem_scan_rate) {
   1290                     idx_count = soc->mem_scan_rate - entries_interval;
   1291                 }
   1292 
   1293                 SOC_MEM_SCAN_READ_LOCK(unit, mem, ser_flags);
   1294                     
   1295                 /*
   1296                  * The size of tables like L3_DEFIP and L3_DEFIP_PAIR_128
   1297                  * can change dynamically. Always do the max_index check
   1298                  */
   1299                  if (0 != (ser_flags & _SOC_SER_FLAG_SIZE_VERIFY)) {
   1300                      if (idx + idx_count - 1 > soc_mem_index_max(unit, mem)) {
   1301                         SOC_MEM_SCAN_READ_UNLOCK(unit, mem, ser_flags);
   1302                         break;
   1303                      }
   1304                  }
   1305 
   1306                  if (soc_feature(unit, soc_feature_memscan_ifp_slice_adjust)) {
   1307                      rv = _soc_memscan_ifp_slice_adjust(unit, table_info, &idx,
   1308                                                         &idx_count);
   1309                      if (SOC_FAILURE(rv)) {
   1310                          LOG_ERROR(BSL_LS_SOC_COMMON,
   1311                                    (BSL_META_U(unit,
   1312                                                "soc_mem_scan_thread: _soc_memscan_ifp_slice_adjust failed: %s\n"),
   1313                                     soc_errmsg(rv)));
   1314                          soc_event_generate(unit,
   1315                                             SOC_SWITCH_EVENT_THREAD_ERROR, 
   1316                                             SOC_SWITCH_EVENT_THREAD_MEMSCAN, 
   1317                                             __LINE__, rv);
   1318                          SOC_MEM_SCAN_READ_UNLOCK(unit, mem, ser_flags);
   1319                          return rv;
   1320                      }
   1321                      if (idx_count == 0) {
   1322                          goto skipped_read;
   1323                      }
   1324                  }
   1325 
   1326 #if defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT)
   1327 #if defined(SOC_UNIQUE_ACC_TYPE_ACCESS)
   1328                 LOG_VERBOSE(BSL_LS_SOC_SOCMEM,
   1329                             (BSL_META_U(unit,
   1330                                         "Scan: unit=%d %s%s.%s[%d-%d]\n"), unit, 
   1331                              SOC_MEM_NAME(unit, mem), 
   1332                              soc_feature(unit, soc_feature_unique_acc_type_access) ?
   1333                              _SOC_MEMSCAN_UNIQUE_ACC_PIPE_NAME(ser_flags & _SOC_SER_FLAG_ACC_TYPE_MASK) :
   1334                              (ser_flags & _SOC_SER_FLAG_ACC_TYPE_MASK) ?
   1335                              "(Y)" : "",
   1336                              SOC_BLOCK_NAME(unit, blk),
   1337                              idx, idx + idx_count - 1));
   1338 #else /* SOC_UNIQUE_ACC_TYPE_ACCESS */
   1339                 LOG_VERBOSE(BSL_LS_SOC_SOCMEM,
   1340                             (BSL_META_U(unit,
   1341                                         "Scan: unit=%d %s%s.%s[%d-%d]\n"), unit, 
   1342                              SOC_MEM_NAME(unit, mem), 
   1343                              (ser_flags & _SOC_SER_FLAG_ACC_TYPE_MASK) ?
   1344                              "(Y)" : "",
   1345                              SOC_BLOCK_NAME(unit, blk),
   1346                              idx, idx + idx_count - 1));
   1347 #endif /* SOC_UNIQUE_ACC_TYPE_ACCESS */
   1348 #endif /* defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT) */
   1349 
   1350 #if defined(BCM_TRIDENT2_SUPPORT)
   1351                 if (soc_mem_fp_global_mask_tcam_cache_update_get(unit)) {
   1352                     soc_mem_fp_global_mask_tcam_cache_update(unit, chunk_size, read_buf);
   1353                 }
   1354 #endif
   1355                 if (0 != (ser_flags & _SOC_SER_FLAG_XY_READ)) {
   1356                     rv = soc_mem_ser_read_range(unit, mem, blk,
   1357                                                 idx, idx + idx_count - 1,
   1358                                                 ser_flags, read_buf);
   1359                 } else {
   1360                     rv = soc_mem_read_range(unit, mem, blk,
   1361                                             idx, idx + idx_count - 1, 
   1362                                             read_buf); 	           
   1363                 }
   1364 
   1365                 if (rv < 0) {
   1366                     LOG_ERROR(BSL_LS_SOC_COMMON,
   1367                               (BSL_META_U(unit,
   1368                                           "soc_mem_scan_thread: TCAM read failed: %s\n"),
   1369                                           soc_errmsg(rv)));
   1370                     soc_event_generate(unit,
   1371                                        SOC_SWITCH_EVENT_THREAD_ERROR, 
   1372                                        SOC_SWITCH_EVENT_THREAD_MEMSCAN, 
   1373                                        __LINE__, rv);
   1374                     SOC_MEM_SCAN_READ_UNLOCK(unit, mem, ser_flags);
   1375                     return rv;
   1376                 }
   1377 
   1378                 skipped_read:
   1379 
   1380                 entries_interval += idx_count;
   1381                 test_count = 
   1382                     (ser_flags & _SOC_SER_FLAG_SW_COMPARE) ? idx_count : 0;
   1383 
   1384                 for (i = 0; i < test_count; i++) {
   1385                     if (soc->mem_scan_interval == 0) {
   1386                         break;
   1387                     }
   1388 
   1389 #ifdef BCM_TRIDENT2PLUS_SUPPORT
   1390                     if ((FP_TCAMm == mem) || (FP_GM_FIELDSm == mem)
   1391                         || (FP_GLOBAL_MASK_TCAMm == mem)
   1392                         || (FP_GLOBAL_MASK_TCAM_Xm == mem)
   1393                         || (FP_GLOBAL_MASK_TCAM_Ym == mem)) {
   1394                         if (soc_mem_test_skip(unit, mem, idx + i) == TRUE) {
   1395                             continue;
   1396                         }
   1397                     }
   1398 #endif
   1399 
   1400 #ifdef BCM_APACHE_SUPPORT
   1401                     if ((VFP_TCAMm == mem) || (EFP_TCAMm == mem)) {
   1402                         if (soc_mem_test_skip(unit, mem, idx + i) == TRUE) {
   1403                             continue;
   1404                         }
   1405                     }
   1406 #endif /* BCM_APACHE_SUPPORT */
   1407 
   1408                     if (0 != (ser_flags & _SOC_SER_FLAG_OVERLAY)) {
   1409                         if (0 != (ser_flags & _SOC_SER_FLAG_OVERLAY_CASE)) {
   1410                             if (!SHR_BITGET(overlay_bitmap, idx + i)) {
   1411                                 /* Not this table view, skip entry */
   1412                                 continue;
   1413                             }
   1414                         } else {
   1415                             if (SHR_BITGET(overlay_bitmap, idx + i)) {
   1416                                 /* Not this table view, skip entry */
   1417                                 continue;
   1418                             }
   1419                         }
   1420                     }
   1421 
   1422                     hw_entry = &(read_buf[i * entry_dw]);
   1423                     if (CACHE_VMAP_TST(vmap, idx + i)) {
   1424                         cmp_entry = &(cache[(idx + i) * entry_dw]);
   1425                     } else {
   1426                         cmp_entry = null_entry;
   1427                     }
   1428  
   1429                     for (dw = 0; dw < entry_dw; dw++) {
   1430                         if (((hw_entry[dw] ^ cmp_entry[dw]) &
   1431                              mask[dw]) != 0) {
   1432                             break;
   1433                         }
   1434                     }
   1435                     if (dw < entry_dw) {
   1436 #if defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT)
   1437                         LOG_WARN(BSL_LS_SOC_COMMON,
   1438                                  (BSL_META_U(unit,
   1439                                              "Memory error detected on unit %d "
   1440                                              "in %s%s.%s[%d]\n"), unit, 
   1441                                   SOC_MEM_NAME(unit, mem),
   1442                                   (ser_flags & _SOC_SER_FLAG_ACC_TYPE_MASK) ?
   1443                                   "(Y)" : "",
   1444                                   SOC_BLOCK_NAME(unit, blk),
   1445                                   idx + i));
   1446 #endif
   1447 
   1448 #ifdef BCM_ESW_SUPPORT
   1449                         error_index = idx + i;
   1450                         errstr[0] = 0;
   1451                         for (dw = 0; dw < entry_dw; dw++) {
   1452                             sal_sprintf(errstr + sal_strlen(errstr),
   1453                                         " %08x", 
   1454                                         cmp_entry[dw]);
   1455                         }
   1456                         LOG_WARN(BSL_LS_SOC_COMMON,
   1457                                  (BSL_META_U(unit,
   1458                                              "    WAS:%s\n"), errstr));
   1459 
   1460                         errstr[0] = 0;
   1461                         for (dw = 0; dw < entry_dw; dw++) {
   1462                             sal_sprintf(errstr + sal_strlen(errstr),
   1463                                         " %08x", 
   1464                                         hw_entry[dw]);
   1465                         }
   1466                         LOG_WARN(BSL_LS_SOC_COMMON,
   1467                                  (BSL_META_U(unit,
   1468                                              "    BAD:%s\n"), errstr));
   1469 
   1470                         err_addr = soc_mem_addr_get(unit, mem, 0, blk, 
   1471                                       error_index, &at);
   1472                         soc_event_generate(unit,
   1473                                            SOC_SWITCH_EVENT_PARITY_ERROR,
   1474                                            SOC_SWITCH_EVENT_DATA_ERROR_PARITY,
   1475                                            err_addr,
   1476                                            0);
   1477                         stat->ser_err_tcam++;
   1478                         sal_memset(&spci, 0, sizeof(spci));
   1479                         spci.flags = SOC_SER_SRC_MEM | SOC_SER_REG_MEM_KNOWN;
   1480                         spci.reg = INVALIDr;
   1481                         spci.mem = mem;
   1482                         spci.blk_type = blk;
   1483                         spci.index = error_index;
   1484                         if (0 == (ser_flags & _SOC_SER_FLAG_ACC_TYPE_MASK)) {
   1485                             spci.acc_type = at;
   1486                             spci.pipe_num = 0;
   1487                         } else {
   1488                             spci.acc_type =
   1489                                 ser_flags & _SOC_SER_FLAG_ACC_TYPE_MASK;
   1490                             spci.pipe_num = 1;
   1491                         }
   1492                         if ((rv = soc_ser_correction(unit, &spci)) < 0) {
   1493                             LOG_WARN(BSL_LS_SOC_COMMON,
   1494                                      (BSL_META_U(unit,
   1495                                                  "    CORRECTION FAILED: %s\n"), 
   1496                                       soc_errmsg(rv)));
   1497                             soc_event_generate(unit, 
   1498                                       SOC_SWITCH_EVENT_THREAD_ERROR,
   1499                                       SOC_SWITCH_EVENT_THREAD_MEMSCAN,
   1500                                                __LINE__, rv);
   1501                             SOC_MEM_SCAN_READ_UNLOCK(unit, mem, ser_flags);
   1502                             return rv;
   1503                         }
   1504 #endif /* BCM_ESW_SUPPORT */
   1505                     } 
   1506                     entries_pass++;
   1507                 }
   1508 
   1509                 SOC_MEM_SCAN_READ_UNLOCK(unit, mem, ser_flags);
   1510             
   1511                 if ((interval = soc->mem_scan_interval) != 0) {
   1512                     if (entries_interval == soc->mem_scan_rate) {
   1513                         sal_sem_take(soc->mem_scan_notify, interval);
   1514                         entries_interval = 0;
   1515                     }
   1516                 } else {
   1517                     return rv;
   1518                 }
   1519             }
   1520         }
   1521     } 
   1522     LOG_INFO(BSL_LS_SOC_TESTS,
   1523              (BSL_META_U(unit,
   1524                          "Done: %d mem scan iterations\n"), ++scan_iter));
   1525 
   1526     return rv;
   1527 }
   1528 
   1529 #ifdef BCM_ESW_SUPPORT
   1530 #define _SOC_MEM_FIELD_CLEAR(unit, mem, entry, field)                  \
   1531         if (SOC_MEM_FIELD_VALID(unit, mem, field)) {                   \
   1532             if (soc_mem_field_length(unit, mem, field) > 32) {         \
   1533                 soc_mem_field64_set(unit, mem, entry, field, val64);   \
   1534             } else {                                                   \
   1535                 soc_mem_field32_set(unit, mem, entry, field, 0);       \
   1536             }                                                          \
   1537         }
   1538 
   1539 STATIC void
   1540 _soc_mem_scan_dynamic_fields_clear(int unit, soc_mem_t mem, uint32 *entry)
   1541 {
   1542     uint64 val64;
   1543     COMPILER_64_ZERO(val64);
   1544     /* Clear parity bits */
   1545     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, PARITYf);
   1546     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, EVEN_PARITYf);
   1547     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, EVEN_PARITY_0f);
   1548     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, EVEN_PARITY_1f);
   1549     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, EVEN_PARITY_2f); 
   1550     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, EVEN_PARITY_3f);
   1551     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, EVEN_PARITY_Af);
   1552     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, EVEN_PARITY_Bf);
   1553     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, EVEN_PARITY_LOWERf);
   1554     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, EVEN_PARITY_UPPERf);
   1555     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, EVEN_PARITY_P0f);
   1556     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, EVEN_PARITY_P1f);
   1557     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, EVEN_PARITY_P2f);
   1558     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, EVEN_PARITY_P3f);
   1559     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, EVEN_PBM_PARITY_P0f);
   1560     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, EVEN_PBM_PARITY_P1f);
   1561     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, EVEN_PBM_PARITY_P2f);
   1562     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, EVEN_PBM_PARITY_P3f);
   1563     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, EVEN_EGR_VLAN_STG_PARITY_P0f);
   1564     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, EVEN_EGR_VLAN_STG_PARITY_P1f);
   1565     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, EVEN_EGR_VLAN_STG_PARITY_P2f);
   1566     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, EVEN_EGR_VLAN_STG_PARITY_P3f);
   1567     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, ECCf);
   1568     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, ECC_0f);
   1569     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, ECC_1f);
   1570     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, ECC_2f);
   1571     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, ECC_3f);
   1572     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, ECC_4f);
   1573     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, ECCPf);
   1574     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, ECCP0f);
   1575     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, ECCP1f);
   1576     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, ECCP2f);
   1577     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, ECCP3f);
   1578     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, ECCP4f);
   1579     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, ECCP5f);
   1580     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, ECCP6f);
   1581     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, ECCP7f);
   1582     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, ECCP_0f);
   1583     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, ECCP_1f);
   1584     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, ECCP_2f);
   1585     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, ECCP_3f);
   1586     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, ECCP_4f);
   1587     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, ECC0f);
   1588     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, ECC1f);
   1589     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, ECC2f);
   1590     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, ECC3f);
   1591     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, PARITY0f);
   1592     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, PARITY1f);
   1593     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, PARITY2f);
   1594     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, PARITY3f);
   1595     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, PARITY_0f);
   1596     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, PARITY_1f);
   1597     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, PARITY_2f);
   1598     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, PARITY_3f);
   1599     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, PARITY_4f);
   1600     /* Clear hit bits */
   1601     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, HITf);
   1602     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, HIT0f);
   1603     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, HIT1f);
   1604     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, HIT_0f);
   1605     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, HIT_1f);
   1606     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, HIT_2f);
   1607     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, HIT_3f);
   1608     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, HITDA_0f);
   1609     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, HITDA_1f);
   1610     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, HITDA_2f);
   1611     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, HITDA_3f);
   1612     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, HITSA_0f);
   1613     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, HITSA_1f);
   1614     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, HITSA_2f);
   1615     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, HITSA_3f);
   1616     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, HITDAf);
   1617     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, HITSAf); 
   1618     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, B0_HITf); 
   1619     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, B1_HITf); 
   1620     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, L3_HIT_DCMf); 
   1621     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, L3_HIT_PMf);
   1622     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, HIT_BITSf);
   1623     /* Clear hardware-modified fields in meter tables  */
   1624     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, BUCKETCOUNTf);
   1625     _SOC_MEM_FIELD_CLEAR(unit, mem, entry, REFRESHCOUNTf);
   1626 }
   1627 #endif
   1628 
   1629 #if defined(BCM_TRIDENT2_SUPPORT)
   1630 void soc_mem_fp_global_mask_tcam_cache_update_set(int unit, int update)
   1631 {
   1632      cache_need_update[unit] = update;
   1633 }
   1634 
   1635 int soc_mem_fp_global_mask_tcam_cache_update_get(int unit)
   1636 {
   1637     return cache_need_update[unit];
   1638 }
   1639 
   1640 void soc_mem_fp_global_mask_tcam_cache_update(int unit, int chunk_size,
   1641                                               uint32 *read_buf)
   1642 {
   1643     int idx_min = 0;
   1644     int idx_max = 0;
   1645     int idx_count = 0;
   1646     int num_tables = 0;
   1647     int ser_idx = 0;
   1648     int entry_dw = 0;
   1649     int idx = 0;
   1650     int dw = 0;
   1651     int pipe = 0;
   1652     int idx_rate = 0;
   1653     int entries_interval = 0;
   1654     int blk = 0;
   1655     int rv = SOC_E_NONE;
   1656     uint32 flags = 0;
   1657     uint32 *cache = NULL;
   1658     uint32 *entry_x, *entry_y;
   1659     soc_mem_t mem = INVALIDm;
   1660     soc_control_t   *soc = SOC_CONTROL(unit);
   1661     _soc_mem_scan_table_info_t *table_info = NULL;
   1662 #ifdef BCM_TRIDENT2PLUS_SUPPORT
   1663     uint32 *mask = NULL;
   1664     soc_pbmp_t pbmp_data, pbmp_mask;
   1665     _soc_mem_scan_table_info_t *table_info_tmp = NULL;
   1666 #endif
   1667 
   1668     if (soc_mem_fp_global_mask_tcam_cache_update_get(unit) &&
   1669         (SOC_IS_TRIDENT2X(unit) || SOC_IS_TITAN2X(unit))) {
   1670 
   1671         mem = FP_GLOBAL_MASK_TCAMm;
   1672         if (soc_mem_cache_get(unit, mem, MEM_BLOCK_ALL) == FALSE) {
   1673             soc_mem_fp_global_mask_tcam_cache_update_set(unit, FALSE);
   1674             return;
   1675         }
   1676         idx_min = soc_mem_index_min(unit, mem);
   1677         idx_max = soc_mem_index_max(unit, mem);
   1678         idx_count = soc_mem_index_count(unit, mem);
   1679         entry_dw = soc_mem_entry_words(unit, mem);
   1680 
   1681         if (NULL == scan_info[unit]) {
   1682             (void)_soc_mem_scan_info_init(unit);
   1683         }
   1684         num_tables = scan_info[unit]->num_tables;
   1685 
   1686         for (ser_idx = 0; ser_idx < num_tables; ser_idx++) {
   1687             table_info = _MEM_SCAN_TABLE_INFO(unit, ser_idx);
   1688             if (mem == table_info->mem) {
   1689                 break;
   1690             }
   1691         }
   1692 
   1693         flags = table_info->ser_flags;
   1694         SOC_MEM_SCAN_READ_LOCK(unit, mem, flags);
   1695         SOC_MEM_BLOCK_ITER(unit, mem, blk) {
   1696             if (!soc_mem_dmaable(unit, mem, blk)) {
   1697                 flags |= _SOC_SER_FLAG_NO_DMA;
   1698             }
   1699 
   1700             for(pipe = 0; pipe < NUM_PIPE(unit); pipe++) {
   1701                 if (pipe == 0) {
   1702                     cache = SOC_MEM_STATE(unit, mem).cache[blk];
   1703 #ifdef BCM_TRIDENT2PLUS_SUPPORT
   1704                     if (SOC_IS_TD2P_TT2P(unit)) {
   1705                         table_info_tmp = _MEM_SCAN_TABLE_INFO(unit, ser_idx);
   1706                         mask = table_info_tmp->mask;
   1707                         soc_mem_pbmp_field_get(unit, mem, mask,
   1708                                                IPBMf, &pbmp_data);
   1709                         soc_mem_pbmp_field_get(unit, mem, mask,
   1710                                                IPBM_MASKf, &pbmp_mask);
   1711                         SOC_PBMP_AND(pbmp_data, PBMP_XPIPE(unit));
   1712                         SOC_PBMP_AND(pbmp_mask, PBMP_XPIPE(unit));
   1713                         soc_mem_pbmp_field_set(unit, mem, mask,
   1714                                                IPBMf, &pbmp_data);
   1715                         soc_mem_pbmp_field_set(unit, mem, mask,
   1716                                                IPBM_MASKf, &pbmp_mask);
   1717                     }
   1718 #endif
   1719                 } else {
   1720                     flags |= _SOC_MEM_ADDR_ACC_TYPE_PIPE_Y;
   1721                     cache = table_info->xy_tcam_cache;
   1722 #ifdef BCM_TRIDENT2PLUS_SUPPORT
   1723                     if (SOC_IS_TD2P_TT2P(unit)) {
   1724                         table_info_tmp = _MEM_SCAN_TABLE_INFO(unit, ser_idx + 1);
   1725                         mask = table_info_tmp->mask;
   1726                         soc_mem_pbmp_field_get(unit, mem, mask,
   1727                                                IPBMf, &pbmp_data);
   1728                         soc_mem_pbmp_field_get(unit, mem, mask,
   1729                                                IPBM_MASKf, &pbmp_mask);
   1730                         SOC_PBMP_AND(pbmp_data, PBMP_YPIPE(unit));
   1731                         SOC_PBMP_AND(pbmp_mask, PBMP_YPIPE(unit));
   1732                         soc_mem_pbmp_field_set(unit, mem, mask,
   1733                                                IPBMf, &pbmp_data);
   1734                         soc_mem_pbmp_field_set(unit, mem, mask,
   1735                                                IPBM_MASKf, &pbmp_mask);
   1736                     }
   1737 #endif
   1738                 }
   1739                 if (cache != NULL) {
   1740                     for (idx = idx_min; idx < idx_max; idx += idx_rate) {
   1741                         idx_rate = idx_max - idx + 1;
   1742 
   1743                         if (idx_rate > chunk_size) {
   1744                             idx_rate = chunk_size;
   1745                         }
   1746 
   1747                         if (entries_interval + idx_rate > soc->mem_scan_rate) {
   1748                             idx_rate = soc->mem_scan_rate - entries_interval;
   1749                         }
   1750                         rv = soc_mem_ser_read_range(unit, mem, blk, idx,
   1751                                                     idx + idx_rate -1, flags, read_buf);
   1752                         if (rv < 0) {
   1753                             SOC_MEM_SCAN_READ_UNLOCK(unit, mem, flags);
   1754                             return;
   1755                         }
   1756                         sal_memcpy(&cache[idx * entry_dw], read_buf,
   1757                                    idx_rate * entry_dw * 4);
   1758                         entries_interval += idx_rate;
   1759 
   1760                         if (entries_interval >= soc->mem_scan_rate) {
   1761                             entries_interval = 0;
   1762                         }
   1763                     }
   1764                 }
   1765             }
   1766 
   1767             cache = SOC_MEM_STATE(unit, mem).cache[blk];
   1768             if (NUM_PIPE(unit) > 1) {
   1769                 for(idx = idx_min; idx < idx_max; idx++) {
   1770                     entry_x = &cache[idx * entry_dw];
   1771                     entry_y = &table_info->xy_tcam_cache[idx * entry_dw];
   1772 
   1773                     /* Put pbmp data in pipe_x and pipe_y together, and update cache data*/
   1774                     for(dw = 0; dw < entry_dw; dw++) {
   1775                         entry_y[dw] |= entry_x[dw];
   1776                     }
   1777                 }
   1778                 _soc_mem_tcam_xy_to_dm(unit, mem, idx_count,
   1779                                        table_info->xy_tcam_cache, cache);
   1780             } else {
   1781                 sal_memcpy(table_info->xy_tcam_cache, cache,
   1782                            idx_count * entry_dw * 4);
   1783                 _soc_mem_tcam_xy_to_dm(unit, mem, idx_count, cache, cache);
   1784             }
   1785         }
   1786         soc_mem_fp_global_mask_tcam_cache_update_set(unit, FALSE);
   1787         SOC_MEM_SCAN_READ_UNLOCK(unit, mem, flags);
   1788     }
   1789 }
   1790 #endif
   1791 
   1792 /*
   1793  * Function:
   1794  * 	_soc_mem_scan_thread (internal)
   1795  * Purpose:
   1796  *   	Thread control for L2 shadow table maintenance
   1797  * Parameters:
   1798  *	unit_vp - StrataSwitch unit # (as a void *).
   1799  * Returns:
   1800  *	Nothing
   1801  * Notes:
   1802  *	Exits when mem_scan_interval is set to zero and semaphore is given.
   1803  */
   1804 
   1805 STATIC void
   1806 _soc_mem_scan_thread(void *unit_vp)
   1807 {
   1808     int			unit = PTR_TO_INT(unit_vp);
   1809     soc_control_t	*soc = SOC_CONTROL(unit);
   1810     int			rv;
   1811     int			interval;
   1812     int			chunk_size;
   1813     int			entries_interval;
   1814     int			entries_pass;
   1815     uint32		*read_buf = NULL;
   1816     uint32		mask[SOC_MAX_MEM_WORDS];
   1817     soc_mem_t		mem;
   1818     int			entry_dw;
   1819     int			blk;
   1820     int			idx, idx_count, i, dw;
   1821     uint32		*cache = NULL;
   1822     uint8		*vmap = NULL;
   1823     char        thread_name[SAL_THREAD_NAME_MAX_LEN];
   1824     sal_thread_t thread;
   1825     int     pipe, num_pipe;
   1826     int     ser_flags[SOC_MAX_NUM_PIPES];
   1827     int     non_tcam_iterations = 0;
   1828     int     dedicated_sram_scan = 0;
   1829     int     non_tcam_pass = 0;
   1830 #ifdef BCM_ESW_SUPPORT
   1831     _soc_ser_correct_info_t spci;
   1832     uint32  error_index;
   1833 #endif
   1834 #ifdef BCM_SRAM_SCAN_SUPPORT
   1835     sal_usecs_t sram_scan_interval = 0;
   1836     int     sram_scan_rate = 0;
   1837 #endif
   1838 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_TRIDENT2PLUS_SUPPORT)
   1839     if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TD2P_TT2P(unit) || SOC_IS_APACHE(unit)) {
   1840         dedicated_sram_scan = 1;
   1841     }
   1842 #endif
   1843     if (SAL_BOOT_SIMULATION || dedicated_sram_scan) { 
   1844         non_tcam_iterations = 0; 
   1845     } else { 
   1846         non_tcam_iterations = soc_property_get(unit, spn_MEM_SCAN_NON_TCAM_ITERATIONS, 0); 
   1847     }
   1848     chunk_size = soc_property_get(unit, spn_MEM_SCAN_CHUNK_SIZE, 256);
   1849 
   1850     read_buf = soc_cm_salloc(unit, chunk_size * SOC_MAX_MEM_WORDS * 4,
   1851                              "mem_scan_new");
   1852 
   1853     if (read_buf == NULL) {
   1854         LOG_ERROR(BSL_LS_SOC_COMMON,
   1855                   (BSL_META_U(unit,
   1856                               "soc_mem_scan_thread: not enough memory, exiting\n")));
   1857         soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
   1858                            SOC_SWITCH_EVENT_THREAD_MEMSCAN, __LINE__, 
   1859                            SOC_E_MEMORY);
   1860         goto cleanup_exit;
   1861     }
   1862 
   1863     /*
   1864      * Implement the sleep using a semaphore timeout so if the task is
   1865      * requested to exit, it can do so immediately.
   1866      */
   1867 
   1868     sal_memset(&ser_flags, 0, sizeof(ser_flags));
   1869     entries_interval = 0;
   1870     thread = sal_thread_self();
   1871     thread_name[0] = 0;
   1872     sal_thread_name(thread, thread_name, sizeof (thread_name));
   1873     while ((interval = soc->mem_scan_interval) != 0) {
   1874         entries_pass = 0;
   1875         if (soc_feature(unit, soc_feature_ser_parity)) {
   1876 #if defined(BCM_TOMAHAWK_SUPPORT)
   1877             if (soc_feature(unit, soc_feature_th_a0_sw_war)) {
   1878                 (void) soc_th_scan_idb_mem_ecc_status(unit);
   1879             }
   1880 #endif /* BCM_TOMAHAWK_SUPPORT */
   1881 
   1882             /* coverity[stack_use_overflow : FALSE] */
   1883             rv = _soc_mem_scan_ser_read_ranges(unit, chunk_size, read_buf);
   1884             
   1885             if (rv < 0) {
   1886                 LOG_ERROR(BSL_LS_SOC_COMMON,
   1887                           (BSL_META_U(unit,
   1888                                       "AbnormalThreadExit:%s, TCAM scan failed: %s\n"),
   1889                            thread_name,
   1890                            soc_errmsg(rv)));
   1891                 soc_event_generate(unit,
   1892                                    SOC_SWITCH_EVENT_THREAD_ERROR, 
   1893                                    SOC_SWITCH_EVENT_THREAD_MEMSCAN, 
   1894                                    __LINE__, rv);
   1895                 goto cleanup_exit;
   1896             }
   1897             if (soc->mem_scan_interval != 0) {
   1898                 sal_sem_take(soc->mem_scan_notify, interval);
   1899                 entries_interval = 0;
   1900             }
   1901             if (non_tcam_iterations == 0 || dedicated_sram_scan == 1) {
   1902                 /* Ignore non-tcam tables */
   1903                 continue;
   1904             }
   1905 #ifdef BCM_SRAM_SCAN_SUPPORT
   1906             if (soc_sram_scan_running(unit, &sram_scan_rate, &sram_scan_interval)) {
   1907                 /* Non-tcam table scan is conducted in dedicated sram scan thread */
   1908                 continue;
   1909             }
   1910 #endif
   1911         }
   1912 
   1913         for (mem = 0; mem < NUM_SOC_MEM; mem++) {
   1914             if (!SOC_MEM_IS_VALID(unit, mem)) {
   1915                 continue;
   1916             }
   1917             if (soc_feature(unit, soc_feature_ser_parity)) {
   1918                 if ((SOC_MEM_INFO(unit, mem).flags &
   1919                       SOC_MEM_FLAG_SER_ENGINE)) {
   1920 #if defined(BCM_ESW_SUPPORT)
   1921                     LOG_VERBOSE(BSL_LS_SOC_SER, (BSL_META_U(unit, "nti_scrub: skipping mem %s (SOC_MEM_FLAG_SER_ENGINE is set)\n"), SOC_MEM_NAME(unit, mem)));
   1922 #endif
   1923                     /* Handled separately */
   1924                     continue;
   1925                 }
   1926             }
   1927             if (!soc_mem_cache_get(unit, mem, MEM_BLOCK_ALL)) {
   1928 #if defined(BCM_ESW_SUPPORT)
   1929                    LOG_VERBOSE(BSL_LS_SOC_SER, (BSL_META_U(unit, "nti_scrub: skipping mem %s (NOT_CACHEABLE)\n"), SOC_MEM_NAME(unit, mem)));
   1930 #endif /* BCM_ESW_SUPPORT */
   1931                    continue;
   1932             }
   1933 #if defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT)
   1934             LOG_VERBOSE(BSL_LS_SOC_SOCMEM,
   1935                         (BSL_META_U(unit,
   1936                                     "Scan mem: %s\n"),
   1937                          SOC_MEM_NAME(unit, mem)));
   1938 #endif
   1939             entry_dw = soc_mem_entry_words(unit, mem);
   1940             soc_mem_datamask_get(unit, mem, mask);
   1941 #ifdef BCM_ESW_SUPPORT
   1942             /* if a mem has mapped-to (actually-used) mem , skip it */
   1943             if(TRUE == soc_mem_is_mapped_mem(unit, mem)) {
   1944                 LOG_VERBOSE(BSL_LS_SOC_SER, (BSL_META_U(unit, "nti_scrub: skipping mem %s (soc_mem_is_mapped_mem)\n"), SOC_MEM_NAME(unit, mem)));
   1945                 continue;
   1946             }
   1947 
   1948             if ((SOC_MEM_INFO(unit, mem).flags & SOC_MEM_FLAG_DYNAMIC)) {
   1949                 LOG_VERBOSE(BSL_LS_SOC_SER, (BSL_META_U(unit, "nti_scrub: dynamic mem %s (SOC_MEM_FLAG_DYNAMIC is set)\n"), SOC_MEM_NAME(unit, mem)));
   1950                 _soc_mem_scan_dynamic_fields_clear(unit, mem, mask);
   1951             }
   1952             LOG_VERBOSE(BSL_LS_SOC_SER, (BSL_META_U(unit, "nti_scrub: now scrubbing mem %s\n"), SOC_MEM_NAME(unit, mem)));
   1953 #endif
   1954             SOC_MEM_BLOCK_ITER(unit, mem, blk) {
   1955                 if (soc->mem_scan_interval == 0) {
   1956                     break;
   1957                 }
   1958                 num_pipe = 0; /* re-init num_pipe for every mem */
   1959 
   1960                 for (idx = soc_mem_index_min(unit, mem);
   1961                      idx <= soc_mem_index_max(unit, mem);
   1962                      idx += idx_count) {
   1963                     if (soc->mem_scan_interval == 0) {
   1964                         break;
   1965                     }
   1966                     idx_count = soc_mem_index_count(unit, mem) - idx;
   1967                     if (idx_count > chunk_size) {
   1968                         idx_count = chunk_size;
   1969                     }
   1970                     if (entries_interval + idx_count > soc->mem_scan_rate) {
   1971                         idx_count = soc->mem_scan_rate - entries_interval;
   1972                     }
   1973                     MEM_LOCK(unit, mem);
   1974                     /*    coverity[negative_returns : FALSE]    */
   1975                     cache = SOC_MEM_STATE(unit, mem).cache[blk];
   1976                     vmap = SOC_MEM_STATE(unit, mem).vmap[blk];
   1977                     
   1978                     if (!num_pipe) { /* if num_pipe is not already determined */
   1979                         if (NUM_PIPE(unit) == 2) {
   1980                             if (SOC_BLOCK_TYPE(unit, blk) == SOC_BLK_IPIPE ||
   1981                                 SOC_BLOCK_TYPE(unit, blk) == SOC_BLK_EPIPE) {
   1982                                 num_pipe = 2;
   1983                                 if (SOC_IS_TRIDENT3X(unit)) {
   1984                                     ser_flags[0] = _SOC_SER_FLAG_MULTI_PIPE |
   1985                                                    _SOC_MEM_ADDR_ACC_TYPE_PIPE_0;
   1986                                     ser_flags[1] = _SOC_SER_FLAG_MULTI_PIPE |
   1987                                                    _SOC_MEM_ADDR_ACC_TYPE_PIPE_1;
   1988                                 } else {
   1989                                     ser_flags[0] = _SOC_SER_FLAG_MULTI_PIPE |
   1990                                                    _SOC_MEM_ADDR_ACC_TYPE_PIPE_X;
   1991                                     ser_flags[1] = _SOC_SER_FLAG_MULTI_PIPE |
   1992                                                    _SOC_MEM_ADDR_ACC_TYPE_PIPE_Y;
   1993                                 }
   1994                                 if (!soc_mem_dmaable(unit, mem, blk)) {
   1995                                     ser_flags[0] |= _SOC_SER_FLAG_NO_DMA;
   1996                                     ser_flags[1] |= _SOC_SER_FLAG_NO_DMA;
   1997                                 }
   1998                             } else {
   1999                                 num_pipe = 1;
   2000                                 ser_flags[0] = 0;
   2001                                 if (!soc_mem_dmaable(unit, mem, blk)) {
   2002                                     ser_flags[0] |= _SOC_SER_FLAG_NO_DMA;
   2003                                 }
   2004                             }
   2005 #if defined(BCM_TRIDENT_SUPPORT)
   2006                             if ((SOC_IS_TRIDENT(unit) || SOC_IS_TITAN(unit)) &&
   2007                             	  (mem == EGR_VLANm)) {
   2008                                 num_pipe = 1;
   2009                                 ser_flags[0] = _SOC_SER_FLAG_NO_DMA;
   2010                             }
   2011 #endif
   2012                         } else {
   2013                             num_pipe = 1;
   2014                             ser_flags[0] = 0;
   2015                             if (!soc_mem_dmaable(unit, mem, blk)) {
   2016                                 ser_flags[0] |= _SOC_SER_FLAG_NO_DMA;
   2017                             }
   2018                         }
   2019                     }
   2020 
   2021                     for (pipe = 0; pipe < num_pipe; pipe++) {
   2022 #if defined(BCM_ESW_SUPPORT)
   2023                         LOG_VERBOSE(BSL_LS_SOC_SER,
   2024                             (BSL_META_U(unit, "nti_scrub: will now scrub mem %s, pipe %d, range %0d - %0d, ser_flags 0x%x\n"),
   2025                                                   SOC_MEM_NAME(unit, mem), pipe,
   2026                                                   idx, idx + idx_count - 1,
   2027                                                   ser_flags[pipe]));
   2028 #endif
   2029                         rv = soc_mem_ser_read_range(unit, mem, blk, idx, idx + idx_count - 1,  
   2030                                                     ser_flags[pipe], read_buf);
   2031                         if (rv < 0) {
   2032                             LOG_ERROR(BSL_LS_SOC_COMMON,
   2033                                       (BSL_META_U(unit,
   2034                                                   "AbnormalThreadExit:%s, read failed: %s\n"),
   2035                                        thread_name,
   2036                                        soc_errmsg(rv)));
   2037 #if defined(BCM_ESW_SUPPORT)
   2038                             LOG_ERROR(BSL_LS_SOC_COMMON,
   2039                                       (BSL_META_U(unit,
   2040                                                   "mem %s, blk %d, start_addr %0d, end_addr %0d, ser_flags %0x, pipe %0d\n"),
   2041                                        SOC_MEM_NAME(unit, mem), blk, idx, idx +
   2042                                        idx_count - 1, ser_flags[pipe], pipe
   2043                                        ));
   2044 #endif
   2045                             soc_event_generate(unit,
   2046                                                SOC_SWITCH_EVENT_THREAD_ERROR, 
   2047                                                SOC_SWITCH_EVENT_THREAD_MEMSCAN, 
   2048                                                __LINE__, rv);
   2049                             MEM_UNLOCK(unit, mem);
   2050                             goto cleanup_exit;
   2051                         }
   2052 #if defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT)
   2053                         LOG_INFO(BSL_LS_SOC_TESTS,
   2054                                  (BSL_META_U(unit,
   2055                                              "Scan: unit=%d %s.%s[%d-%d]\n"), unit, 
   2056                                   SOC_MEM_NAME(unit, mem), 
   2057                                   SOC_BLOCK_NAME(unit, blk),
   2058                                   idx, idx + idx_count - 1));
   2059 #endif
   2060 
   2061                         for (i = 0; i < idx_count; i++) {
   2062                             if (!CACHE_VMAP_TST(vmap, idx + i)) {
   2063                                 continue;
   2064                             }
   2065                             for (dw = 0; dw < entry_dw; dw++) {
   2066                                 if (((read_buf[i * entry_dw + dw] ^
   2067                                       cache[(idx + i) * entry_dw + dw]) &
   2068                                       mask[dw]) != 0) {
   2069                                     break;
   2070                                 }
   2071                             }
   2072                             if (dw < entry_dw) {
   2073                                 char errstr[80 + SOC_MAX_MEM_WORDS * 9];
   2074 #if defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT)
   2075                                 LOG_WARN(BSL_LS_SOC_COMMON,
   2076                                          (BSL_META_U(unit,
   2077                                                      "Memory error detected on unit %d "
   2078                                                      "in %s.%s[%d]\n"), unit, 
   2079                                           SOC_MEM_NAME(unit, mem),
   2080                                           SOC_BLOCK_NAME(unit, blk),
   2081                                           idx + i));
   2082 #endif
   2083                                 errstr[0] = 0;
   2084                                 for (dw = 0; dw < entry_dw; dw++) {
   2085                                     sal_sprintf(errstr + sal_strlen(errstr),
   2086                                                 " %08x", 
   2087                                                 cache[(idx + i) *
   2088                                                       entry_dw + dw]);
   2089                                 }
   2090                                 LOG_WARN(BSL_LS_SOC_COMMON,
   2091                                          (BSL_META_U(unit,
   2092                                                      "    WAS:%s\n"), errstr));
   2093 
   2094                                 errstr[0] = 0;
   2095                                 for (dw = 0; dw < entry_dw; dw++) {
   2096                                     sal_sprintf(errstr + sal_strlen(errstr),
   2097                                                 " %08x", 
   2098                                                 read_buf[i * entry_dw + dw]);
   2099                                 }
   2100                                 LOG_WARN(BSL_LS_SOC_COMMON,
   2101                                          (BSL_META_U(unit,
   2102                                                      "    BAD:%s\n"), errstr));
   2103 #ifdef BCM_ESW_SUPPORT
   2104                                 if (SOC_IS_ESW(unit)) {
   2105                                     error_index = idx + i;
   2106                                     sal_memset(&spci, 0, sizeof(spci));
   2107                                     spci.flags = SOC_SER_SRC_MEM | SOC_SER_REG_MEM_KNOWN;
   2108                                     spci.reg = INVALIDr;
   2109                                     spci.mem = mem;
   2110                                     spci.blk_type = blk;
   2111                                     spci.index = error_index;
   2112                                     spci.pipe_num = pipe;
   2113                                     spci.acc_type = ser_flags[pipe] & _SOC_SER_FLAG_ACC_TYPE_MASK;
   2114                                     rv = soc_ser_correction(unit, &spci);
   2115                                 } else 
   2116 #endif                                
   2117                                 {
   2118                                     rv = soc_mem_write(unit, mem, blk, idx + i, 
   2119                                                        cache + (idx + i) * entry_dw);
   2120                                 }
   2121 
   2122                                 if (rv < 0) {
   2123                                     LOG_WARN(BSL_LS_SOC_COMMON,
   2124                                             (BSL_META_U(unit,
   2125                                                         "    CORRECTION FAILED: %s\n"), 
   2126                                                         soc_errmsg(rv)));
   2127                                              soc_event_generate(unit, 
   2128                                                  SOC_SWITCH_EVENT_THREAD_ERROR,
   2129                                                  SOC_SWITCH_EVENT_THREAD_MEMSCAN,
   2130                                                  __LINE__, rv);
   2131                                     MEM_UNLOCK(unit, mem);
   2132                                     goto cleanup_exit;
   2133                                 } else {
   2134                                     LOG_WARN(BSL_LS_SOC_COMMON,
   2135                                              (BSL_META_U(unit,
   2136                                                          "    Corrected by writing back cached data\n")));
   2137                                 }
   2138                             }
   2139                             entries_pass++;
   2140                         }
   2141                     }
   2142                     MEM_UNLOCK(unit, mem);
   2143             
   2144                     entries_interval += num_pipe*idx_count;
   2145             
   2146                     if (entries_interval >= soc->mem_scan_rate) {
   2147                         sal_sem_take(soc->mem_scan_notify, interval);
   2148                         entries_interval = 0;
   2149                         
   2150                         if (soc_feature(unit, soc_feature_ser_parity)) {
   2151                             non_tcam_pass++;
   2152                             if (non_tcam_pass == non_tcam_iterations) {
   2153                                 rv = _soc_mem_scan_ser_read_ranges(unit, chunk_size, 
   2154                                                                    read_buf);
   2155                                 if (rv < 0) {
   2156                                     LOG_ERROR(BSL_LS_SOC_COMMON,
   2157                                               (BSL_META_U(unit,
   2158                                                "AbnormalThreadExit:%s, TCAM scan failed: %s\n"),
   2159                                                thread_name,
   2160                                                soc_errmsg(rv)));
   2161                                     soc_event_generate(unit,
   2162                                                        SOC_SWITCH_EVENT_THREAD_ERROR, 
   2163                                                        SOC_SWITCH_EVENT_THREAD_MEMSCAN, 
   2164                                                        __LINE__, rv);
   2165                                     goto cleanup_exit;
   2166                                 }
   2167                                 
   2168                                 if (soc->mem_scan_interval != 0) {
   2169                                     sal_sem_take(soc->mem_scan_notify, interval);
   2170                                     entries_interval = 0;
   2171                                 }
   2172                                 non_tcam_pass = 0;
   2173                             }
   2174                         }
   2175                     } /*at end of mem_scan_rate interval */
   2176                 } /* for each chunk of dma reads */
   2177             } /* for every block_instance of mem */
   2178         } /* for every mem */
   2179 
   2180         LOG_INFO(BSL_LS_SOC_TESTS,
   2181                  (BSL_META_U(unit,
   2182                              "Done: %d mem entries checked\n"), entries_pass));
   2183         if (soc->mem_scan_interval != 0) {
   2184             /* Extra sleep in main loop, in case no caches are enabled. */
   2185             sal_sem_take(soc->mem_scan_notify, interval);
   2186             entries_interval = 0;
   2187         }
   2188     }
   2189 
   2190 cleanup_exit:
   2191 
   2192     if (read_buf != NULL) {
   2193         soc_cm_sfree(unit, read_buf);
   2194     }
   2195 
   2196     soc->mem_scan_pid = SAL_THREAD_ERROR;
   2197     sal_thread_exit(0);
   2198 }
   2199 
   2200 #endif    /* INCLUDE_MEM_SCAN */