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 */