pstats.c (49071B)
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 * Packetized Statistic 8 * Purpose: API to set Packetized Stats registers. 9 */ 10 11 #include <sal/core/libc.h> 12 13 #include <shared/bsl.h> 14 #include <soc/defs.h> 15 16 #if defined(INCLUDE_PSTATS) && defined(BCM_TRIDENT3_SUPPORT) 17 #include <soc/drv.h> 18 #include <soc/mem.h> 19 #include <soc/profile_mem.h> 20 #include <soc/debug.h> 21 #include <soc/trident3.h> 22 #include <soc/pstats.h> 23 24 #include <bcm/error.h> 25 #include <bcm/pstats.h> 26 27 #include <bcm_int/esw/mbcm.h> 28 #include <bcm_int/esw/tomahawk.h> 29 #include <bcm_int/esw/trident3.h> 30 31 #include <bcm_int/esw_dispatch.h> 32 #include <bcm_int/esw/pstats.h> 33 34 #ifdef BCM_WARM_BOOT_SUPPORT 35 #include <bcm_int/esw/switch.h> 36 #endif /* BCM_WARM_BOOT_SUPPORT */ 37 38 #define PSTATS_SESSION_MIN 1 39 #define PSTATS_SESSION_MAX 256 40 /* Max 1 XPEs and 2 PIPEs */ 41 #define TD3_MAX_XPEPIPE _TD3_PIPES_PER_DEV * _TD3_XPES_PER_DEV 42 43 #define TD3_MAX_POOL_COUNT 4 44 #define TD3_MAX_UCQ_COUNT 1328 45 46 /* Max Elements Count = UCQ + ING POOL + EGR POOL */ 47 #define TD3_MAX_ELEMENT_COUNT TD3_MAX_UCQ_COUNT + TD3_MAX_POOL_COUNT * 2 48 49 #define TD3_PORT_NUM_COS(unit, port) \ 50 ((IS_CPU_PORT(unit, port)) ? NUM_CPU_COSQ(unit) : \ 51 (IS_LB_PORT(unit, port)) ? 10 : NUM_COS(unit)) 52 53 /* 54 * Macro to get buffer index 55 * Per XPE or PIPE instance (ING POOL & EGR POOL) 56 * buffer_id = xpe or pipe 57 * ---------------------- 58 * | buffer | pool id | 59 * | 0 | 0 | 60 * | 1 | 1 | 61 * | 2 | 2 | 62 * | 3 | 3 | 63 * ---------------------- 64 * Per XPE-PIPE instance (UCQ) 65 * buffer_id = xpe * NUM_PIPE(unit) + pipe 66 * -------------------- 67 * | buffer | xpe | pipe | 68 * | 0 | 0 | 0 | 69 * | 1 | 0 | 1 | 70 */ 71 #define TD3_XPE_PIPE_INDEX(unit, xpe, pipe) \ 72 (((xpe) == -1) ? (pipe) : \ 73 ((pipe) == -1) ? (xpe) : (xpe) * NUM_PIPE(unit) + (pipe)) 74 75 #define TD3_XPE_VALID(unit, xpe, valid) \ 76 if (xpe > NUM_XPE(unit)) { \ 77 valid = FALSE; \ 78 } \ 79 80 81 typedef struct pstats_session_s { 82 bcm_pstats_session_id_t session_id; 83 84 /* session buffer */ 85 bcm_pstats_timestamp_t timestamp; 86 bcm_pstats_data_t *data_array; 87 88 /* session element info */ 89 int element_array_count; 90 bcm_pstats_session_element_t element_array[TD3_MAX_ELEMENT_COUNT]; 91 92 uint32 enable; 93 94 /* prev session */ 95 struct pstats_session_s *prev_session; 96 /* next session */ 97 struct pstats_session_s *next_session; 98 } pstats_session_t; 99 100 typedef struct pstats_buffer_s { 101 soc_mem_t mem; 102 soc_mem_t clear_mem; 103 int min_idx; 104 int max_idx; 105 int num_entries; 106 uint8 *buf; 107 } pstats_buffer_t; 108 109 typedef struct pstats_control_s { 110 /* full buffer */ 111 #ifdef BCM_PSTATS_MEASURE 112 pstats_buffer_t local_time; 113 pstats_buffer_t local_time_end; 114 #endif 115 pstats_buffer_t utc_time; 116 pstats_buffer_t ucq_buffer[TD3_MAX_XPEPIPE]; 117 pstats_buffer_t ing_pool_buffer[TD3_MAX_POOL_COUNT]; 118 pstats_buffer_t egr_pool_buffer[TD3_MAX_POOL_COUNT]; 119 120 bcm_pstats_session_id_t next_session_id; 121 uint32 session_count; 122 #ifdef BCM_PSTATS_MEASURE 123 uint64 time_cost; 124 #endif 125 int stat_mode; 126 int hw_cor_in_max_use_count; 127 pstats_session_t *first_session; 128 } pstats_control_t; 129 130 static soc_field_t ucq_field[4] = {UCQ_COUNT0f, UCQ_COUNT1f, 131 UCQ_COUNT2f, UCQ_COUNT3f}; 132 static soc_field_t isp_field[4] = {SP0f, SP1f, SP2f, SP3f}; 133 static soc_field_t esp_field[4] = {COUNT_0f, COUNT_1f, 134 COUNT_2f, COUNT_3f}; 135 136 static pstats_control_t pstats_control[BCM_MAX_NUM_UNITS]; 137 #define PSTATS_CTRL(u) pstats_control[u] 138 139 STATIC int 140 bcm_td3_pstats_session_create(int unit, int options, int array_count, 141 bcm_pstats_session_element_t *element_array, 142 bcm_pstats_session_id_t *session_id); 143 STATIC int 144 bcm_td3_pstats_session_destroy(int unit, bcm_pstats_session_id_t session_id); 145 STATIC int 146 bcm_td3_pstats_session_get(int unit, bcm_pstats_session_id_t session_id, 147 int array_max, 148 bcm_pstats_session_element_t *element_array, 149 int *array_count); 150 STATIC int bcm_td3_pstats_data_sync(int unit); 151 STATIC int 152 bcm_td3_pstats_session_data_get(int unit, bcm_pstats_session_id_t session_id, 153 int sync, 154 bcm_pstats_timestamp_t *timestamp, 155 int array_max, 156 bcm_pstats_data_t *data, 157 int *array_count); 158 STATIC int 159 bcm_td3_pstats_session_data_clear(int unit, bcm_pstats_session_id_t session_id); 160 161 STATIC int 162 bcm_td3_pstats_session_traverse(int unit, bcm_pstats_session_traverse_cb cb, 163 void *user_data); 164 165 #ifdef BCM_WARM_BOOT_SUPPORT_SW_DUMP 166 /* 167 * Function: 168 * bcm_td3_pstats_sw_dump 169 * Purpose: 170 * Displays PSTATS information maintained by software. 171 * Parameters: 172 * unit - Device unit number 173 * Returns: 174 * None 175 */ 176 STATIC void 177 bcm_td3_pstats_sw_dump(int unit) 178 { 179 pstats_session_t *cur_session; 180 181 LOG_CLI((BSL_META_U(unit, 182 "=========== \n"))); 183 LOG_CLI((BSL_META_U(unit, "Pstats mode: %s\n"), 184 PSTATS_CTRL(unit).stat_mode ? 185 "Max-use-count" : "Instantaneous")); 186 LOG_CLI((BSL_META_U(unit, "Total pstats session count: %d\n"), 187 PSTATS_CTRL(unit).session_count)); 188 cur_session = PSTATS_CTRL(unit).first_session; 189 while (NULL != cur_session) { 190 LOG_CLI((BSL_META_U(unit, 191 "Pstats session id: %d element count: %d\n"), 192 cur_session->session_id, 193 cur_session->element_array_count)); 194 cur_session = cur_session->next_session; 195 } 196 LOG_CLI((BSL_META_U(unit, 197 "=========== \n"))); 198 return; 199 } 200 #endif /* BCM_WARM_BOOT_SUPPORT_SW_DUMP */ 201 202 STATIC void 203 _bcm_td3_pstats_session_cleanup(int unit, pstats_session_t *session) 204 { 205 session->enable = FALSE; 206 if (NULL != session->data_array) { 207 sal_free(session->data_array); 208 } 209 210 sal_memset(session, 0, sizeof(pstats_session_t)); 211 212 return; 213 } 214 215 STATIC pstats_session_t* 216 _bcm_td3_pstats_session_get(int unit, bcm_pstats_session_id_t session_id) 217 { 218 int found = 0; 219 pstats_session_t *cur_session; 220 221 cur_session = PSTATS_CTRL(unit).first_session; 222 while (NULL != cur_session) { 223 if (cur_session->session_id == session_id) { 224 found = 1; 225 break; 226 } 227 cur_session = cur_session->next_session; 228 } 229 230 if (found) { 231 return cur_session; 232 } 233 234 return NULL; 235 } 236 237 /* Set a minimum available session id */ 238 STATIC void 239 _bcm_td3_pstats_session_next_id_set(int unit) 240 { 241 pstats_session_t *cur_session; 242 bcm_pstats_session_id_t id = PSTATS_SESSION_MIN; 243 244 cur_session = PSTATS_CTRL(unit).first_session; 245 while (NULL != cur_session) { 246 if (id < cur_session->session_id) { 247 break; 248 } else if (id == cur_session->session_id) { 249 /* this id already existed */ 250 id++; 251 } 252 cur_session = cur_session->next_session; 253 } 254 255 PSTATS_CTRL(unit).next_session_id = id; 256 257 LOG_INFO(BSL_LS_BCM_PSTATS, (BSL_META_U(unit, "next %d\n"), id)); 258 } 259 260 STATIC int 261 _bcm_td3_pstats_session_delete(int unit, bcm_pstats_session_id_t session_id) 262 { 263 pstats_session_t *cur_session; 264 265 cur_session = _bcm_td3_pstats_session_get(unit, session_id); 266 if (NULL == cur_session) { 267 LOG_INFO(BSL_LS_BCM_PSTATS, 268 (BSL_META_U(unit, "pstats session %d not found\n"), session_id)); 269 return BCM_E_NOT_FOUND; 270 } 271 /* update session link */ 272 if ((NULL == cur_session->prev_session) && 273 (NULL == cur_session->next_session)) { 274 /* only one session */ 275 PSTATS_CTRL(unit).first_session = NULL; 276 } else if (NULL == cur_session->prev_session) { 277 /* first session */ 278 PSTATS_CTRL(unit).first_session = cur_session->next_session; 279 cur_session->next_session->prev_session = NULL; 280 } else if (NULL == cur_session->next_session) { 281 /* last session */ 282 cur_session->prev_session->next_session = NULL; 283 } else { 284 cur_session->prev_session->next_session = cur_session->next_session; 285 cur_session->next_session->prev_session = cur_session->prev_session; 286 } 287 _bcm_td3_pstats_session_cleanup(unit, cur_session); 288 if (NULL != cur_session) { 289 sal_free(cur_session); 290 } 291 PSTATS_CTRL(unit).session_count--; 292 293 _bcm_td3_pstats_session_next_id_set(unit); 294 295 return BCM_E_NONE; 296 } 297 298 STATIC void 299 _bcm_td3_pstats_session_insert(int unit, pstats_session_t *session) 300 { 301 pstats_session_t *cur_session; 302 bcm_pstats_session_id_t id = session->session_id; 303 304 cur_session = PSTATS_CTRL(unit).first_session; 305 if (NULL == cur_session) { 306 /* first session */ 307 PSTATS_CTRL(unit).first_session = session; 308 session->prev_session = NULL; 309 session->next_session = NULL; 310 } 311 while (NULL != cur_session) { 312 if (id > cur_session->session_id) { 313 /* last session */ 314 if (NULL == cur_session->next_session) { 315 cur_session->next_session = session; 316 session->prev_session = cur_session; 317 session->next_session = NULL; 318 break; 319 } else { 320 cur_session = cur_session->next_session; 321 } 322 } else { 323 /* first session */ 324 if (NULL == cur_session->prev_session) { 325 PSTATS_CTRL(unit).first_session = session; 326 session->prev_session = NULL; 327 session->next_session = cur_session; 328 cur_session->prev_session = session; 329 break; 330 } else { 331 session->prev_session = cur_session->prev_session; 332 session->next_session = cur_session; 333 cur_session->prev_session->next_session = session; 334 cur_session->prev_session = session; 335 break; 336 } 337 break; 338 } 339 } 340 PSTATS_CTRL(unit).session_count++; 341 342 session->enable = TRUE; 343 344 return; 345 } 346 347 STATIC void 348 _bcm_td3_pstats_buffer_deinit(int unit, pstats_buffer_t *pbuf) 349 { 350 if (NULL == pbuf) { 351 return; 352 } 353 354 if (NULL != pbuf->buf) { 355 sal_free(pbuf->buf); 356 } 357 sal_memset(pbuf, 0, sizeof(pstats_buffer_t)); 358 359 return; 360 } 361 362 STATIC int 363 _bcm_td3_pstats_buffer_init(int unit, soc_mem_t mem, soc_mem_t clear_mem, 364 pstats_buffer_t *pbuf) 365 { 366 int alloc_size; 367 368 if (NULL == pbuf) { 369 return BCM_E_PARAM; 370 } 371 372 if (NULL != pbuf->buf) { 373 return BCM_E_PARAM; 374 } 375 376 pbuf->mem = mem; 377 pbuf->clear_mem = clear_mem; 378 pbuf->min_idx = soc_mem_index_min(unit, mem); 379 pbuf->max_idx = soc_mem_index_max(unit, mem); 380 pbuf->num_entries = soc_mem_index_max(unit, mem) + 1; 381 alloc_size = sizeof(uint32) * soc_mem_entry_words(unit, mem); 382 alloc_size *= pbuf->num_entries; 383 384 pbuf->buf = sal_alloc(alloc_size, "pstats buffer"); 385 if (pbuf->buf == NULL) { 386 return BCM_E_MEMORY; 387 } 388 sal_memset(pbuf->buf, 0, alloc_size); 389 390 return BCM_E_NONE; 391 } 392 393 /* 394 * Function: 395 * bcm_td3_pstats_deinit 396 * Purpose: 397 * Deinitialize PSTATS driver functions 398 * for Trident3 (BCM56870). 399 * Parameters: 400 * unit - (IN) StrataSwitch unit number. 401 * Returns: 402 * BCM_E_XXX 403 */ 404 void 405 bcm_td3_pstats_deinit(int unit) 406 { 407 pstats_session_t *cur_session, *next_session; 408 int i; 409 410 soc_pstats_deinit(unit); 411 412 #ifdef BCM_PSTATS_MEASURE 413 _bcm_td3_pstats_buffer_deinit(unit, &PSTATS_CTRL(unit).local_time); 414 _bcm_td3_pstats_buffer_deinit(unit, &PSTATS_CTRL(unit).local_time_end); 415 #endif 416 _bcm_td3_pstats_buffer_deinit(unit, &PSTATS_CTRL(unit).utc_time); 417 for (i = 0; i < TD3_MAX_XPEPIPE; i++) { 418 _bcm_td3_pstats_buffer_deinit(unit, &PSTATS_CTRL(unit).ucq_buffer[i]); 419 } 420 for (i = 0; i < TD3_MAX_POOL_COUNT; i++) { 421 _bcm_td3_pstats_buffer_deinit(unit, &PSTATS_CTRL(unit).ing_pool_buffer[i]); 422 _bcm_td3_pstats_buffer_deinit(unit, &PSTATS_CTRL(unit).egr_pool_buffer[i]); 423 } 424 425 cur_session = PSTATS_CTRL(unit).first_session; 426 while (NULL != cur_session) { 427 next_session = cur_session->next_session; 428 _bcm_td3_pstats_session_cleanup(unit, cur_session); 429 if (NULL != cur_session) { 430 sal_free(cur_session); 431 } 432 PSTATS_CTRL(unit).session_count--; 433 cur_session = next_session; 434 } 435 436 if (PSTATS_CTRL(unit).session_count != 0) { 437 /* debug info */ 438 } 439 sal_memset(&PSTATS_CTRL(unit), 0, sizeof(pstats_control_t)); 440 441 return; 442 } 443 444 445 /* 446 * Function: 447 * bcm_td3_pstats_init 448 * Purpose: 449 * Initialize PSTATS driver functions 450 * for Trident3 (BCM56970). 451 * Parameters: 452 * unit - (IN) StrataSwitch unit number. 453 * Returns: 454 * BCM_E_XXX 455 */ 456 int 457 bcm_td3_pstats_init(int unit) 458 { 459 _bcm_pstats_unit_driver_t *pstats_driver; 460 pstats_buffer_t *pbuf; 461 int rv = BCM_E_NONE; 462 soc_mem_t mem, clear_mem, base_mem; 463 int index, pipe, xpe; 464 uint32 flag; 465 466 if (2 != soc_property_get(unit, spn_BUFFER_STATS_COLLECT_TYPE, 1)) { 467 LOG_INFO(BSL_LS_BCM_PSTATS, 468 (BSL_META_U(unit, "current mode is not pstats, no need init\n"))); 469 return BCM_E_NONE; 470 } 471 472 pstats_driver = _BCM_PSTATS_UNIT_DRIVER(unit); 473 if (pstats_driver == NULL) { 474 return BCM_E_MEMORY; 475 } 476 477 /* Initializing Driver functions for PSTATS */ 478 pstats_driver->session_create = bcm_td3_pstats_session_create; 479 pstats_driver->session_destroy = bcm_td3_pstats_session_destroy; 480 pstats_driver->session_get = bcm_td3_pstats_session_get; 481 pstats_driver->data_sync = bcm_td3_pstats_data_sync; 482 pstats_driver->session_data_get = bcm_td3_pstats_session_data_get; 483 pstats_driver->session_data_clear = bcm_td3_pstats_session_data_clear; 484 pstats_driver->session_traverse = bcm_td3_pstats_session_traverse; 485 #ifdef BCM_WARM_BOOT_SUPPORT_SW_DUMP 486 pstats_driver->pstats_sw_dump = bcm_td3_pstats_sw_dump; 487 #endif 488 489 /* alloc buffer for full pstats table */ 490 #ifdef BCM_PSTATS_MEASURE 491 /* local time */ 492 mem = MMU_INTFO_TIMESTAMPm; 493 pbuf = &PSTATS_CTRL(unit).local_time; 494 rv = _bcm_td3_pstats_buffer_init(unit, mem, mem, pbuf); 495 if (BCM_FAILURE(rv)) { 496 goto cleanup; 497 } 498 mem = MMU_INTFO_TIMESTAMPm; 499 pbuf = &PSTATS_CTRL(unit).local_time_end; 500 rv = _bcm_td3_pstats_buffer_init(unit, mem, mem, pbuf); 501 if (BCM_FAILURE(rv)) { 502 goto cleanup; 503 } 504 #endif 505 506 /* utc time */ 507 mem = MMU_INTFO_UTC_TIMESTAMPm; 508 pbuf = &PSTATS_CTRL(unit).utc_time; 509 rv = _bcm_td3_pstats_buffer_init(unit, mem, mem, pbuf); 510 if (BCM_FAILURE(rv)) { 511 goto cleanup; 512 } 513 514 /* ucq buffer */ 515 base_mem = MMU_THDU_UCQ_STATS_TABLEm; 516 for (pipe = 0; pipe < NUM_PIPE(unit); pipe++) { 517 for (xpe = 0; xpe < NUM_XPE(unit); xpe++) { 518 mem = SOC_MEM_UNIQUE_ACC_XPE_PIPE(unit, base_mem, xpe, pipe); 519 clear_mem = SOC_MEM_UNIQUE_ACC_XPE_PIPE(unit, MMU_THDU_UCQ_STATSm, 520 xpe, pipe); 521 if (mem == INVALIDm) { 522 continue; 523 } 524 525 index = TD3_XPE_PIPE_INDEX(unit, xpe, pipe); 526 if (index >= TD3_MAX_XPEPIPE) { 527 rv = BCM_E_INTERNAL; 528 goto cleanup; 529 } 530 pbuf = &PSTATS_CTRL(unit).ucq_buffer[index]; 531 532 rv = _bcm_td3_pstats_buffer_init(unit, mem, clear_mem, pbuf); 533 if (BCM_FAILURE(rv)) { 534 goto cleanup; 535 } 536 } 537 } /* ucq buffer */ 538 539 /* ing pool buffer */ 540 base_mem = THDI_PKT_STAT_SP_SHARED_COUNTm; 541 for (xpe = 0; xpe < NUM_XPE(unit); xpe++) { 542 mem = SOC_MEM_UNIQUE_ACC(unit, base_mem)[xpe]; 543 if (mem == INVALIDm) { 544 continue; 545 } 546 547 index = TD3_XPE_PIPE_INDEX(unit, xpe, -1); 548 if (index >= TD3_MAX_POOL_COUNT) { 549 rv = BCM_E_INTERNAL; 550 goto cleanup; 551 } 552 553 pbuf = &PSTATS_CTRL(unit).ing_pool_buffer[index]; 554 555 rv = _bcm_td3_pstats_buffer_init(unit, mem, mem, pbuf); 556 if (BCM_FAILURE(rv)) { 557 goto cleanup; 558 } 559 } /* ing pool buffer */ 560 561 /* egr pool buffer */ 562 base_mem = MMU_THDM_DB_POOL_MCUC_PKSTATm; 563 for (xpe = 0; xpe < NUM_XPE(unit); xpe++) { 564 mem = SOC_MEM_UNIQUE_ACC(unit, base_mem)[xpe]; 565 if (mem == INVALIDm) { 566 continue; 567 } 568 569 index = TD3_XPE_PIPE_INDEX(unit, xpe, -1); 570 if (index >= TD3_MAX_POOL_COUNT) { 571 rv = BCM_E_INTERNAL; 572 goto cleanup; 573 } 574 575 pbuf = &PSTATS_CTRL(unit).egr_pool_buffer[index]; 576 577 rv = _bcm_td3_pstats_buffer_init(unit, mem, mem, pbuf); 578 if (BCM_FAILURE(rv)) { 579 goto cleanup; 580 } 581 } /* egr pool buffer */ 582 583 PSTATS_CTRL(unit).next_session_id = PSTATS_SESSION_MIN; 584 585 rv = soc_pstats_init(unit); 586 if (BCM_FAILURE(rv)) { 587 LOG_INFO(BSL_LS_SOC_COMMON, 588 (BSL_META_U(unit, "soc_pstats_init failed rv = %d\n"), rv)); 589 goto cleanup; 590 } 591 592 #ifdef BCM_WARM_BOOT_SUPPORT 593 if (SOC_WARM_BOOT(unit)) { 594 int config; 595 596 /* get pstats config from HW */ 597 rv = soc_trident3_mmu_pstats_mode_get(unit, &flag); 598 if (BCM_FAILURE(rv)) { 599 goto cleanup; 600 } 601 602 /* HW config is different with config property */ 603 if (!(flag & _TD3_MMU_PSTATS_ENABLE) || 604 !(flag & _TD3_MMU_PSTATS_PKT_MOD)) { 605 LOG_ERROR(BSL_LS_SOC_COMMON, 606 (BSL_META_U(unit, 607 "WARMBOOT ERROR.\n" 608 "Current buffer stats mode is not pstats.\n"))); 609 rv = BCM_E_INIT; 610 goto cleanup; 611 } 612 613 if (flag & _TD3_MMU_PSTATS_HWM_MOD) { 614 PSTATS_CTRL(unit).stat_mode = 1; 615 if (flag & _TD3_MMU_PSTATS_RESET_ON_READ) { 616 PSTATS_CTRL(unit).hw_cor_in_max_use_count = 1; 617 } else { 618 PSTATS_CTRL(unit).hw_cor_in_max_use_count = 0; 619 } 620 } else { 621 PSTATS_CTRL(unit).stat_mode = 0; 622 PSTATS_CTRL(unit).hw_cor_in_max_use_count = 0; 623 } 624 625 config = soc_property_get(unit, spn_BUFFER_STATS_COLLECT_MODE, 0); 626 if (config != PSTATS_CTRL(unit).stat_mode) { 627 LOG_WARN(BSL_LS_SOC_COMMON, 628 (BSL_META_U(unit, 629 "WARMBOOT WARNING.\n" 630 "Config mode %d. HW mode %d.\n"), 631 config, PSTATS_CTRL(unit).stat_mode)); 632 } 633 634 flag |= _TD3_MMU_PSTATS_SYNC | _TD3_MMU_PSTATS_MOR_EN; 635 636 /* Reset pstats mode in warmboot */ 637 rv = soc_trident3_mmu_pstats_mode_set(unit, flag); 638 if (BCM_FAILURE(rv)) { 639 goto cleanup; 640 } 641 } else 642 #endif 643 { 644 PSTATS_CTRL(unit).stat_mode = 645 soc_property_get(unit, spn_BUFFER_STATS_COLLECT_MODE, 0); 646 if ((PSTATS_CTRL(unit).stat_mode == 1) && 647 soc_property_get(unit, "oob_pstats_hw_cor_en", 1)) { 648 PSTATS_CTRL(unit).hw_cor_in_max_use_count = 1; 649 } 650 651 /* call soc function */ 652 flag = _TD3_MMU_PSTATS_ENABLE | 653 _TD3_MMU_PSTATS_PKT_MOD | 654 _TD3_MMU_PSTATS_SYNC | 655 _TD3_MMU_PSTATS_MOR_EN; 656 657 658 if (PSTATS_CTRL(unit).stat_mode) { 659 flag |= _TD3_MMU_PSTATS_HWM_MOD; 660 if (PSTATS_CTRL(unit).hw_cor_in_max_use_count == 1) { 661 flag |= _TD3_MMU_PSTATS_RESET_ON_READ; 662 } 663 } 664 665 rv = soc_trident3_mmu_pstats_mode_set(unit, flag); 666 if (BCM_FAILURE(rv)) { 667 goto cleanup; 668 } 669 } 670 671 return BCM_E_NONE; 672 673 cleanup: 674 soc_pstats_deinit(unit); 675 (void )bcm_td3_pstats_deinit(unit); 676 677 return rv; 678 } 679 680 STATIC int 681 _bcm_td3_pstats_session_element_check(int unit, 682 bcm_pstats_session_element_t element) 683 { 684 bcm_gport_t gport; 685 bcm_port_t local_port; 686 bcm_cos_queue_t cosq; 687 688 LOG_INFO(BSL_LS_BCM_PSTATS, 689 (BSL_META_U(unit, "pstats_session_element_check unit %d\n"), unit)); 690 691 if (element.type == bcmPStatsSessionUnicastQueue) { 692 gport = element.gport; 693 cosq = element.cosq; 694 if (BCM_GPORT_IS_SET(gport)) { 695 if (BCM_GPORT_IS_LOCAL(gport)) { 696 local_port = BCM_GPORT_LOCAL_GET(gport); 697 } else if (BCM_GPORT_IS_MODPORT(gport)) { 698 BCM_IF_ERROR_RETURN( 699 bcm_esw_port_local_get(unit, gport, &local_port)); 700 } else if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 701 return BCM_E_NONE; 702 } else { 703 LOG_INFO(BSL_LS_BCM_PSTATS, 704 (BSL_META_U(unit, "pstats_session_element_check: " 705 "gport 0x%x is illegal!\n"), gport)); 706 return BCM_E_PARAM; 707 } 708 } else { 709 local_port = gport; 710 } 711 712 if (!SOC_PORT_VALID(unit, local_port) || IS_CPU_PORT(unit, local_port)) { 713 LOG_INFO(BSL_LS_BCM_PSTATS, 714 (BSL_META_U(unit, "pstats_session_element_check: " 715 "gport 0x%x is illegal!\n"), gport)); 716 return BCM_E_PORT; 717 } 718 /* cosq check when gport is a port gport */ 719 if ((cosq < 0) || (cosq >= TD3_PORT_NUM_COS(unit, local_port))) { 720 LOG_INFO(BSL_LS_BCM_PSTATS, 721 (BSL_META_U(unit, "pstats_session_element_check: " 722 "cosq %d is illegal!\n"), cosq)); 723 return BCM_E_PARAM; 724 } 725 } else if ((element.type == bcmPStatsSessionIngPool) || 726 (element.type == bcmPStatsSessionEgrPool)) { 727 if ((element.pool < 0) || (element.pool >= TD3_MAX_POOL_COUNT)) { 728 LOG_INFO(BSL_LS_BCM_PSTATS, 729 (BSL_META_U(unit, "pstats_session_element_check: " 730 "pool_id %d is illegal!\n"), element.pool)); 731 return BCM_E_PARAM; 732 } 733 } else { 734 LOG_INFO(BSL_LS_BCM_PSTATS, 735 (BSL_META_U(unit, "pstats_session_element_check: " 736 "unknow element type %d\n"), element.type)); 737 return BCM_E_PARAM; 738 } 739 740 return BCM_E_NONE; 741 } 742 743 744 /* 745 * Function: 746 * bcm_td3_pstats_session_create 747 * Purpose: 748 * Create a PKT STAT session instance for SDK management. 749 * Parameters: 750 * unit - (IN) StrataSwitch unit number. 751 * options - (IN) BCM_PSTATS_REPLACE: replace existing. 752 * BCM_PSTATS_WITH_ID: session_id argument is given. 753 * array_count - (IN) Number of elements in array. 754 * element_array - (IN) PSTATS session element array. 755 * session_id - (INOUT) id of a PSTATS session created via this API. 756 * Returns: 757 * BCM_E_XXX 758 */ 759 STATIC int 760 bcm_td3_pstats_session_create(int unit, int options, int array_count, 761 bcm_pstats_session_element_t *element_array, 762 bcm_pstats_session_id_t *session_id) 763 { 764 int rv, i, alloc_size; 765 bcm_pstats_session_id_t id = 0; 766 pstats_session_t *cur_session = NULL; 767 768 LOG_INFO(BSL_LS_BCM_PSTATS, 769 (BSL_META_U(unit, "pstats_session_create unit %d options %d " 770 "array_count %d\n"), unit, options, array_count)); 771 772 /* element check */ 773 if ((array_count < 0) || 774 (array_count > TD3_MAX_ELEMENT_COUNT)) { 775 LOG_ERROR(BSL_LS_BCM_PSTATS, 776 (BSL_META_U(unit, "array_count %d is illegal!\n"), array_count)); 777 return BCM_E_PARAM; 778 } 779 if (NULL == element_array) { 780 LOG_ERROR(BSL_LS_BCM_PSTATS, 781 (BSL_META_U(unit, "element_array is null\n"))); 782 return BCM_E_PARAM; 783 } 784 785 for (i = 0; i < array_count; i++) { 786 BCM_IF_ERROR_RETURN( 787 _bcm_td3_pstats_session_element_check(unit, element_array[i])); 788 } 789 790 if (options & BCM_PSTATS_OPTIONS_REPLACE) { 791 /* delete original session first */ 792 id = *session_id; 793 BCM_IF_ERROR_RETURN(_bcm_td3_pstats_session_delete(unit, id)); 794 } else if (options & BCM_PSTATS_OPTIONS_WITH_ID) { 795 id = *session_id; 796 if (id < PSTATS_SESSION_MIN) { 797 LOG_ERROR(BSL_LS_BCM_PSTATS, 798 (BSL_META_U(unit, "input session_id %d is illegal!\n"), id)); 799 return BCM_E_PARAM; 800 } 801 cur_session = _bcm_td3_pstats_session_get(unit, id); 802 if (NULL != cur_session) { 803 LOG_INFO(BSL_LS_BCM_PSTATS, 804 (BSL_META_U(unit, "pstats_session_create: " 805 "session_id %d is existed\n"), id)); 806 return BCM_E_EXISTS; 807 } 808 } else { 809 id = PSTATS_CTRL(unit).next_session_id; 810 } 811 812 /* SDK has a limitation of maxium session count */ 813 if (PSTATS_CTRL(unit).session_count >= PSTATS_SESSION_MAX) { 814 LOG_INFO(BSL_LS_BCM_PSTATS, 815 (BSL_META_U(unit, "pstats_session_create: " 816 "session count is full\n"))); 817 return BCM_E_FULL; 818 } 819 820 cur_session = 821 (pstats_session_t*) sal_alloc(sizeof(pstats_session_t), 822 "pstats session"); 823 if (NULL == cur_session) { 824 return BCM_E_MEMORY; 825 } 826 sal_memset(cur_session, 0, sizeof(pstats_session_t)); 827 828 /* record session info */ 829 cur_session->session_id = id; 830 cur_session->element_array_count = array_count; 831 sal_memcpy(cur_session->element_array, 832 element_array, 833 array_count * sizeof(bcm_pstats_session_element_t)); 834 835 alloc_size = array_count * sizeof(bcm_pstats_data_t); 836 cur_session->data_array = sal_alloc(alloc_size, "data array"); 837 if (NULL == cur_session->data_array) { 838 rv = BCM_E_MEMORY; 839 goto cleanup; 840 } 841 sal_memset(cur_session->data_array, 0, alloc_size); 842 843 _bcm_td3_pstats_session_insert(unit, cur_session); 844 _bcm_td3_pstats_session_next_id_set(unit); 845 846 *session_id = id; 847 return BCM_E_NONE; 848 cleanup: 849 _bcm_td3_pstats_session_cleanup(unit, cur_session); 850 if (NULL != cur_session) { 851 sal_free(cur_session); 852 } 853 return rv; 854 } 855 856 /* 857 * Function: 858 * bcm_td3_pstats_session_destroy 859 * Purpose: 860 * Destroy an existing PSTATS session. 861 * Parameters: 862 * unit - (IN) StrataSwitch unit number. 863 * session_id - (IN) id of a PSTATS session created via the 864 * bcm_pkt==stats_session_create 865 * Returns: 866 * BCM_E_XXX 867 */ 868 STATIC int 869 bcm_td3_pstats_session_destroy(int unit, 870 bcm_pstats_session_id_t session_id) 871 { 872 return _bcm_td3_pstats_session_delete(unit, session_id); 873 } 874 875 /* 876 * Function: 877 * bcm_td3_pstats_session_get 878 * Purpose: 879 * Get an existing PSTATS session info. 880 * Parameters: 881 * unit - (IN) StrataSwitch unit number. 882 * session_id - (IN) id of a PSTATS session created via the 883 * bcm_pstats_session_create 884 * array_max - (IN) Maximum number of elements in array. 885 * element_array - (OUT) element array of a PSTATS session. 886 * array_count - (OUT) Number of elements in array. 887 * Returns: 888 * BCM_E_XXX 889 */ 890 STATIC int 891 bcm_td3_pstats_session_get(int unit, 892 bcm_pstats_session_id_t session_id, 893 int array_max, 894 bcm_pstats_session_element_t *element_array, 895 int *array_count) 896 { 897 pstats_session_t *cur_session = NULL; 898 899 LOG_INFO(BSL_LS_BCM_PSTATS, 900 (BSL_META_U(unit, "pstats_session_get unit %d session_id %d\n"), 901 unit, session_id)); 902 903 if (NULL == element_array) { 904 LOG_ERROR(BSL_LS_BCM_PSTATS, 905 (BSL_META_U(unit, "element_array is null\n"))); 906 return BCM_E_PARAM; 907 } 908 909 cur_session = _bcm_td3_pstats_session_get(unit, session_id); 910 if (NULL == cur_session) { 911 LOG_INFO(BSL_LS_BCM_PSTATS, 912 (BSL_META_U(unit, "pstats session %d not found\n"), session_id)); 913 return BCM_E_NOT_FOUND; 914 } 915 916 if (array_max >= cur_session->element_array_count) { 917 *array_count = cur_session->element_array_count; 918 } else if (array_max >= 0) { 919 *array_count = array_max; 920 } else { 921 return BCM_E_PARAM; 922 } 923 924 sal_memcpy(element_array, 925 cur_session->element_array, 926 *array_count * sizeof(bcm_pstats_session_element_t)); 927 928 return BCM_E_NONE; 929 } 930 931 STATIC int 932 _bcm_td3_pstats_session_data_update(int unit, 933 bcm_pstats_session_element_t element, 934 bcm_pstats_data_t *data) 935 { 936 bcm_gport_t gport; 937 bcm_port_t local_port; 938 bcm_cos_queue_t cosq; 939 bcm_service_pool_id_t pool; 940 int index, pen_idx = 0; 941 int mode, i, xpe, pipe, startq, offset; 942 uint8 *total_buf; 943 uint32 cur_val = 0, *pre_p; 944 void *pentry; 945 soc_info_t *si = &SOC_INFO(unit); 946 soc_mem_t mem; 947 soc_field_t field; 948 949 mode = PSTATS_CTRL(unit).stat_mode; 950 951 if (element.type == bcmPStatsSessionUnicastQueue) { 952 /* update ucq use counts 953 * ucq_buf: 954 * 0-1 each XPE has two pipes */ 955 gport = element.gport; 956 cosq = element.cosq; 957 BCM_IF_ERROR_RETURN( 958 _bcm_td3_cosq_index_resolve(unit, gport, cosq, 959 _BCM_TD3_COSQ_INDEX_STYLE_UCAST_QUEUE, 960 &local_port, &startq, NULL)); 961 pipe = si->port_pipe[local_port]; 962 963 for (xpe = 0, i = 0; xpe < NUM_XPE(unit); xpe++) { 964 965 if(!((si->epipe_xpe_map[pipe] >> xpe) & 1)) { 966 continue; 967 } 968 index = TD3_XPE_PIPE_INDEX(unit, xpe, pipe); 969 if (index >= TD3_MAX_XPEPIPE) { 970 return BCM_E_INTERNAL; 971 } 972 total_buf = PSTATS_CTRL(unit).ucq_buffer[index].buf; 973 mem = PSTATS_CTRL(unit).ucq_buffer[index].mem; 974 /* In TD3, due to physical bank is 332 deep, when read out 975 * index='d82, it will read out 2 valid counter at location 'd328 976 * and 'd329, plus 2 invalid counter at location 'd330 and 'd331 */ 977 if (startq >= 330) { 978 startq += 2; 979 } 980 pen_idx = startq / 4; 981 offset = startq % 4; 982 pentry = soc_mem_table_idx_to_pointer(unit, mem, void*, 983 total_buf, pen_idx); 984 cur_val = soc_mem_field32_get(unit, mem, pentry, ucq_field[offset]); 985 986 pre_p = &data->use_counts_array[i]; 987 if (mode) { 988 if (cur_val > *pre_p) { 989 *pre_p = cur_val; 990 } 991 } else { 992 *pre_p = cur_val; 993 } 994 i++; 995 } 996 data->array_count = i; 997 } else { 998 /* update pool use counts 999 * pool_buf: 1000 * xpe0-p0 1001 */ 1002 pool = element.pool; 1003 for (xpe = 0, i = 0; xpe < NUM_XPE(unit); xpe++) { 1004 index = TD3_XPE_PIPE_INDEX(unit, xpe, -1); 1005 if (index >= TD3_MAX_POOL_COUNT) { 1006 return BCM_E_INTERNAL; 1007 } 1008 1009 if (element.type == bcmPStatsSessionIngPool) { 1010 total_buf = PSTATS_CTRL(unit).ing_pool_buffer[xpe].buf; 1011 mem = PSTATS_CTRL(unit).ing_pool_buffer[xpe].mem; 1012 field = isp_field[pool]; 1013 } else if (element.type == bcmPStatsSessionEgrPool) { 1014 total_buf = PSTATS_CTRL(unit).egr_pool_buffer[xpe].buf; 1015 mem = PSTATS_CTRL(unit).egr_pool_buffer[xpe].mem; 1016 field = esp_field[pool]; 1017 } else { 1018 return BCM_E_INTERNAL; 1019 } 1020 1021 pentry = soc_mem_table_idx_to_pointer(unit, mem, void*, 1022 total_buf, pen_idx); 1023 cur_val = soc_mem_field32_get(unit, mem, pentry, field); 1024 pre_p = &data->use_counts_array[i]; 1025 if (mode) { 1026 if (cur_val > *pre_p) { 1027 *pre_p = cur_val; 1028 } 1029 } else { 1030 *pre_p = cur_val; 1031 } 1032 i++; 1033 } 1034 data->array_count = i; 1035 } 1036 1037 return BCM_E_NONE; 1038 } 1039 1040 STATIC int 1041 _bcm_td3_pstats_session_update(int unit, pstats_session_t *session) 1042 { 1043 bcm_pstats_session_element_t element; 1044 bcm_pstats_data_t *data; 1045 pstats_session_t *cur_session = session; 1046 uint8 *total_buf; 1047 int i; 1048 void *pentry; 1049 soc_mem_t mem; 1050 1051 /* update timestamp 1052 * if MMU_INTFO_TOD_TIMESTAMP is updated by ARM core, 1053 * MMU_INTFO_UTC_TIMESTAMP is a utc time. 1054 * otherwise it is a local time. 1055 */ 1056 total_buf = PSTATS_CTRL(unit).utc_time.buf; 1057 mem = PSTATS_CTRL(unit).utc_time.mem; 1058 pentry = soc_mem_table_idx_to_pointer(unit, mem, void*, total_buf, 0); 1059 cur_session->timestamp.nanoseconds = 1060 soc_mem_field32_get(unit, mem, pentry, UTC_TIMESTAMP_NSECf); 1061 soc_mem_field64_get(unit, mem, pentry, UTC_TIMESTAMP_SECf, 1062 &cur_session->timestamp.seconds); 1063 1064 #ifdef BCM_PSTATS_MEASURE 1065 if (soc_property_get(unit, "pstats_timestamp_info", 0) == 1) { 1066 COMPILER_64_TO_32_LO(cur_session->timestamp.nanoseconds, 1067 PSTATS_CTRL(unit).time_cost); 1068 } 1069 #endif 1070 1071 /* update element data */ 1072 for (i = 0; i < cur_session->element_array_count; i++) { 1073 element = cur_session->element_array[i]; 1074 data = &cur_session->data_array[i]; 1075 BCM_IF_ERROR_RETURN( 1076 _bcm_td3_pstats_session_data_update(unit, element, data)); 1077 } 1078 1079 return BCM_E_NONE; 1080 } 1081 1082 /* 1083 * Function: 1084 * _bcm_td3_pstats_hw_sync 1085 * Purpose: 1086 * Start a pstats sync operation. 1087 * Parameters: 1088 * unit - (IN) StrataSwitch unit number 1089 * Returns: 1090 * BCM_E_XXX 1091 */ 1092 STATIC int 1093 _bcm_td3_pstats_hw_sync(int unit) 1094 { 1095 pstats_buffer_t *pbuf; 1096 int index, pipe, xpe; 1097 soc_info_t *si = &SOC_INFO(unit); 1098 #ifdef BCM_PSTATS_MEASURE 1099 void *pentry; 1100 uint64 start_ts, end_ts; 1101 #endif 1102 1103 SOC_IF_ERROR_RETURN(soc_pstats_sync(unit)); 1104 1105 #ifdef BCM_PSTATS_MEASURE 1106 /* sync local time */ 1107 pbuf = &PSTATS_CTRL(unit).local_time; 1108 SOC_IF_ERROR_RETURN( 1109 soc_pstats_mem_get(unit, pbuf->mem, pbuf->buf, 0)); 1110 pentry = soc_mem_table_idx_to_pointer(unit, pbuf->mem, void*, 1111 pbuf->buf, 0); 1112 soc_mem_field64_get(unit, pbuf->mem, pentry, TIMESTAMPf, &start_ts); 1113 1114 pbuf = &PSTATS_CTRL(unit).local_time_end; 1115 SOC_IF_ERROR_RETURN( 1116 soc_pstats_mem_get(unit, pbuf->mem, pbuf->buf, 1)); 1117 pentry = soc_mem_table_idx_to_pointer(unit, pbuf->mem, void*, 1118 pbuf->buf, 0); 1119 soc_mem_field64_get(unit, pbuf->mem, pentry, TIMESTAMPf, &end_ts); 1120 1121 LOG_INFO(BSL_LS_BCM_PSTATS, 1122 (BSL_META_U(unit, "start 0x%x%8x end 0x%x%8x\n"), 1123 COMPILER_64_HI(start_ts), COMPILER_64_LO(start_ts), 1124 COMPILER_64_HI(end_ts), COMPILER_64_LO(end_ts))); 1125 1126 /* handle rollover */ 1127 if (COMPILER_64_LT(end_ts, start_ts)) { 1128 uint64 wrap_amt; 1129 int width; 1130 1131 width = soc_mem_field_length(unit, MMU_INTFO_TIMESTAMPm, TIMESTAMPf); 1132 COMPILER_64_SET(wrap_amt, 1UL << (width - 32), 0); 1133 COMPILER_64_ADD_64(end_ts, wrap_amt); 1134 } 1135 COMPILER_64_DELTA(PSTATS_CTRL(unit).time_cost, start_ts, end_ts); 1136 #endif 1137 1138 1139 /* sync utc time */ 1140 pbuf = &PSTATS_CTRL(unit).utc_time; 1141 SOC_IF_ERROR_RETURN( 1142 soc_pstats_mem_get(unit, pbuf->mem, pbuf->buf, 0)); 1143 1144 /* sync uc queue */ 1145 for (pipe = 0; pipe < NUM_PIPE(unit); pipe++) { 1146 for (xpe = 0; xpe < NUM_XPE(unit); xpe++) { 1147 1148 if(!((si->epipe_xpe_map[pipe] >> xpe) & 1)) { 1149 continue; 1150 } 1151 index = TD3_XPE_PIPE_INDEX(unit, xpe, pipe); 1152 if (index >= TD3_MAX_XPEPIPE) { 1153 return BCM_E_INTERNAL; 1154 } 1155 pbuf = &PSTATS_CTRL(unit).ucq_buffer[index]; 1156 SOC_IF_ERROR_RETURN( 1157 soc_pstats_mem_get(unit, pbuf->mem, pbuf->buf, 0)); 1158 } 1159 } 1160 1161 /* sync ing pool */ 1162 for (xpe = 0; xpe < NUM_XPE(unit); xpe++) { 1163 1164 index = TD3_XPE_PIPE_INDEX(unit, xpe, -1); 1165 if (index >= TD3_MAX_POOL_COUNT) { 1166 return BCM_E_INTERNAL; 1167 } 1168 pbuf = &PSTATS_CTRL(unit).ing_pool_buffer[index]; 1169 SOC_IF_ERROR_RETURN( 1170 soc_pstats_mem_get(unit, pbuf->mem, pbuf->buf, 0)); 1171 } 1172 1173 /* sync egr pool */ 1174 for (xpe = 0; xpe < NUM_XPE(unit); xpe++) { 1175 1176 index = TD3_XPE_PIPE_INDEX(unit, xpe, -1); 1177 if (index >= TD3_MAX_POOL_COUNT) { 1178 return BCM_E_INTERNAL; 1179 } 1180 pbuf = &PSTATS_CTRL(unit).egr_pool_buffer[index]; 1181 SOC_IF_ERROR_RETURN( 1182 soc_pstats_mem_get(unit, pbuf->mem, pbuf->buf, 0)); 1183 } 1184 1185 return BCM_E_NONE; 1186 } 1187 1188 /* 1189 * Function: 1190 * _bcm_td3_pstats_session_data_sync 1191 * Purpose: 1192 * Start a pstats sync operation for a special session 1193 * Parameters: 1194 * unit - (IN) StrataSwitch unit number 1195 * Returns: 1196 * BCM_E_XXX 1197 */ 1198 STATIC int 1199 _bcm_td3_pstats_session_data_sync(int unit, pstats_session_t *session) 1200 { 1201 BCM_IF_ERROR_RETURN(_bcm_td3_pstats_hw_sync(unit)); 1202 BCM_IF_ERROR_RETURN(_bcm_td3_pstats_session_update(unit, session)); 1203 return BCM_E_NONE; 1204 } 1205 1206 /* 1207 * Function: 1208 * bcm_td3_pstats_data_sync 1209 * Purpose: 1210 * Start a pstats sync operation. 1211 * Parameters: 1212 * unit - (IN) StrataSwitch unit number 1213 * Returns: 1214 * BCM_E_XXX 1215 */ 1216 STATIC int 1217 bcm_td3_pstats_data_sync(int unit) 1218 { 1219 pstats_session_t *cur_session = NULL; 1220 sal_usecs_t start_time = sal_time_usecs(); 1221 1222 BCM_IF_ERROR_RETURN(_bcm_td3_pstats_hw_sync(unit)); 1223 LOG_DEBUG(BSL_LS_SOC_COMMON, 1224 (BSL_META_U(unit, "Time taken for pstats dma: %d usec\n"), 1225 SAL_USECS_SUB(sal_time_usecs(), start_time))); 1226 cur_session = PSTATS_CTRL(unit).first_session; 1227 while (NULL != cur_session) { 1228 if (cur_session->enable != TRUE) { 1229 continue; 1230 } 1231 BCM_IF_ERROR_RETURN( 1232 _bcm_td3_pstats_session_update(unit, cur_session)); 1233 cur_session = cur_session->next_session; 1234 } 1235 return BCM_E_NONE; 1236 } 1237 1238 /* 1239 * Function: 1240 * bcm_td3_pstats_session_data_get 1241 * Purpose: 1242 * Get an existing PSTATS session data. 1243 * Parameters: 1244 * unit - (IN) StrataSwitch unit number 1245 * session_id - (IN) id of a PSTATS session created via the 1246 * bcm_pstats_session_create 1247 * sync - (IN) Need a sync operation 1248 * timestamp - (OUT) time stamp info. 1249 * array_max - (IN) Maximum number of elements in array. 1250 * data - (OUT) array of use count data. 1251 * array_count - (OUT) Number of elements in array. 1252 * Returns: 1253 * BCM_E_XXX 1254 */ 1255 STATIC int 1256 bcm_td3_pstats_session_data_get(int unit, bcm_pstats_session_id_t session_id, 1257 int sync, 1258 bcm_pstats_timestamp_t *timestamp, 1259 int array_max, 1260 bcm_pstats_data_t *data_array, 1261 int *array_count) 1262 { 1263 pstats_session_t *cur_session = NULL; 1264 int mode; 1265 1266 LOG_INFO(BSL_LS_BCM_PSTATS, 1267 (BSL_META_U(unit, "pstats_session_data_get unit %d session_id %d " 1268 "sync %d\n"), unit, session_id, sync)); 1269 1270 if (NULL == data_array) { 1271 LOG_ERROR(BSL_LS_BCM_PSTATS, 1272 (BSL_META_U(unit, "data_array is null\n"))); 1273 return BCM_E_PARAM; 1274 } 1275 1276 mode = PSTATS_CTRL(unit).stat_mode; 1277 cur_session = _bcm_td3_pstats_session_get(unit, session_id); 1278 if (NULL == cur_session) { 1279 LOG_INFO(BSL_LS_BCM_PSTATS, 1280 (BSL_META_U(unit, "pstats_session_data_get: " 1281 "session_id %d is not found\n"), session_id)); 1282 return BCM_E_NOT_FOUND; 1283 } 1284 1285 if (array_max >= cur_session->element_array_count) { 1286 *array_count = cur_session->element_array_count; 1287 } else if (array_max >= 0) { 1288 *array_count = array_max; 1289 } else { 1290 LOG_ERROR(BSL_LS_BCM_PSTATS, 1291 (BSL_META_U(unit, "array_max %d is illegal\n"), array_max)); 1292 return BCM_E_PARAM; 1293 } 1294 1295 /* if PKT STAT mode is HWM, need to sync up all sessions */ 1296 if (TRUE == sync) { 1297 if (mode) { 1298 BCM_IF_ERROR_RETURN(bcm_td3_pstats_data_sync(unit)); 1299 } else { 1300 BCM_IF_ERROR_RETURN( 1301 _bcm_td3_pstats_session_data_sync(unit, cur_session)); 1302 } 1303 } 1304 1305 sal_memcpy(data_array, cur_session->data_array, 1306 *array_count * sizeof(bcm_pstats_data_t)); 1307 1308 sal_memcpy(timestamp, &cur_session->timestamp, sizeof(bcm_pstats_timestamp_t)); 1309 1310 return BCM_E_NONE; 1311 } 1312 1313 STATIC int 1314 _bcm_td3_pstats_session_data_hw_clear(int unit, bcm_pstats_session_element_t element) 1315 { 1316 bcm_gport_t gport; 1317 bcm_port_t local_port; 1318 bcm_cos_queue_t cosq; 1319 bcm_service_pool_id_t pool; 1320 int index, xpe, pipe, startq; 1321 soc_info_t *si = &SOC_INFO(unit); 1322 soc_mem_t mem; 1323 soc_field_t field; 1324 uint32 entry[SOC_MAX_MEM_WORDS]; 1325 1326 if (element.type == bcmPStatsSessionUnicastQueue) { 1327 /* update ucq use counts 1328 * ucq_buf: 1329 * 0-1 each XPE has two pipes */ 1330 gport = element.gport; 1331 cosq = element.cosq; 1332 BCM_IF_ERROR_RETURN( 1333 _bcm_td3_cosq_index_resolve(unit, gport, cosq, 1334 _BCM_TD3_COSQ_INDEX_STYLE_UCAST_QUEUE, 1335 &local_port, &startq, NULL)); 1336 pipe = si->port_pipe[local_port]; 1337 1338 for (xpe = 0; xpe < NUM_XPE(unit); xpe++) { 1339 1340 if(!((si->epipe_xpe_map[pipe] >> xpe) & 1)) { 1341 continue; 1342 } 1343 index = TD3_XPE_PIPE_INDEX(unit, xpe, pipe); 1344 if (index >= TD3_MAX_XPEPIPE) { 1345 return BCM_E_INTERNAL; 1346 } 1347 mem = PSTATS_CTRL(unit).ucq_buffer[index].clear_mem; 1348 SOC_IF_ERROR_RETURN( 1349 soc_mem_read(unit, mem, MEM_BLOCK_ALL, startq, entry)); 1350 soc_mem_field32_set(unit, mem, entry, UCQ_COUNTf, 0); 1351 SOC_IF_ERROR_RETURN( 1352 soc_mem_write(unit, mem, MEM_BLOCK_ALL, startq, entry)); 1353 } 1354 } else { 1355 /* update pool use counts 1356 * pool_buf: 1357 * 0-3 |xpe0-p0|xpe1-p0|xpe2-p0|xpe3-p0| 1358 */ 1359 pool = element.pool; 1360 for (xpe = 0; xpe < NUM_XPE(unit); xpe++) { 1361 1362 index = TD3_XPE_PIPE_INDEX(unit, xpe, -1); 1363 if (index >= TD3_MAX_POOL_COUNT) { 1364 return BCM_E_INTERNAL; 1365 } 1366 1367 if (element.type == bcmPStatsSessionIngPool) { 1368 mem = PSTATS_CTRL(unit).ing_pool_buffer[xpe].clear_mem; 1369 field = isp_field[pool]; 1370 } else if (element.type == bcmPStatsSessionEgrPool) { 1371 mem = PSTATS_CTRL(unit).egr_pool_buffer[xpe].clear_mem; 1372 field = esp_field[pool]; 1373 } else { 1374 return BCM_E_INTERNAL; 1375 } 1376 SOC_IF_ERROR_RETURN( 1377 soc_mem_read(unit, mem, MEM_BLOCK_ALL, 0, entry)); 1378 soc_mem_field32_set(unit, mem, entry, field, 0); 1379 SOC_IF_ERROR_RETURN( 1380 soc_mem_write(unit, mem, MEM_BLOCK_ALL, 0, entry)); 1381 } 1382 } 1383 1384 return BCM_E_NONE; 1385 } 1386 1387 /* 1388 * Function: 1389 * bcm_pstats_session_data_clear 1390 * Purpose: 1391 * Clear an existing PSTATS session hw use counts and sw use counts buffer. 1392 * Parameters: 1393 * unit - (IN) StrataSwitch unit number. 1394 * session_id - (IN) id of a PSTATS session created via the 1395 * bcm_pstats_session_create. 1396 * Returns: 1397 * BCM_E_XXX 1398 */ 1399 STATIC int 1400 bcm_td3_pstats_session_data_clear(int unit, bcm_pstats_session_id_t session_id) 1401 { 1402 bcm_pstats_session_element_t element; 1403 pstats_session_t *cur_session = NULL; 1404 int i, need_hw_clear = 1; 1405 1406 LOG_INFO(BSL_LS_BCM_PSTATS, 1407 (BSL_META_U(unit, "pstats_session_data_clear unit %d session_id %d\n"), 1408 unit, session_id)); 1409 1410 cur_session = _bcm_td3_pstats_session_get(unit, session_id); 1411 if (NULL == cur_session) { 1412 LOG_INFO(BSL_LS_BCM_PSTATS, 1413 (BSL_META_U(unit, "pstats_session_data_clear: " 1414 "session_id %d is not found\n"), session_id)); 1415 return BCM_E_NOT_FOUND; 1416 } 1417 1418 /* clear HW use count buffer */ 1419 if ((PSTATS_CTRL(unit).stat_mode == 1) && 1420 (PSTATS_CTRL(unit).hw_cor_in_max_use_count == 1)) { 1421 /* HW clear on read is enabled, no need do hw clear */ 1422 need_hw_clear = 0; 1423 } 1424 1425 if (need_hw_clear == 1) { 1426 for (i = 0; i < cur_session->element_array_count; i++) { 1427 element = cur_session->element_array[i]; 1428 BCM_IF_ERROR_RETURN( 1429 _bcm_td3_pstats_session_data_hw_clear(unit, element)); 1430 } 1431 } 1432 1433 /* clear SW use count buffer */ 1434 sal_memset(cur_session->data_array, 0, 1435 cur_session->element_array_count * sizeof(bcm_pstats_data_t)); 1436 1437 return BCM_E_NONE; 1438 } 1439 1440 /* 1441 * Function: 1442 * bcm_td3_pstats_session_traverse 1443 * Purpose: 1444 * Traverse through the pstats sessions and run callback at each 1445 * session. 1446 * Parameters: 1447 * unit - (IN) StrataSwitch unit number. 1448 * cb - (IN) bcm_pstats_session_traverse_cb. 1449 * user_data - (IN) User data to be passed to callback function. 1450 * Returns: 1451 * BCM_E_XXX 1452 */ 1453 STATIC int 1454 bcm_td3_pstats_session_traverse(int unit, bcm_pstats_session_traverse_cb cb, 1455 void *user_data) 1456 { 1457 bcm_pstats_session_element_t element_array[TD3_MAX_ELEMENT_COUNT]; 1458 bcm_pstats_session_id_t session_id; 1459 pstats_session_t *cur_session = NULL; 1460 int array_count; 1461 int rv = BCM_E_NONE; 1462 1463 LOG_INFO(BSL_LS_BCM_PSTATS, 1464 (BSL_META_U(unit, "pstats_session_travers unit %d\n"), unit)); 1465 1466 cur_session = PSTATS_CTRL(unit).first_session; 1467 while (NULL != cur_session) { 1468 session_id = cur_session->session_id; 1469 array_count = cur_session->element_array_count; 1470 sal_memcpy(element_array, cur_session->element_array, 1471 array_count * sizeof(bcm_pstats_session_element_t)); 1472 1473 cur_session = cur_session->next_session; 1474 1475 rv = cb(unit, session_id, array_count, element_array, user_data); 1476 #ifdef BCM_CB_ABORT_ON_ERR 1477 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 1478 return rv; 1479 } 1480 #else 1481 /* 1482 * If CB_ABORT_ON_ERR is not defined don't return error 1483 * and continue. 1484 */ 1485 rv = BCM_E_NONE; 1486 #endif 1487 } 1488 1489 return rv; 1490 } 1491 #else /* INCLUDE_PSTATS && BCM_TRIDENT3_SUPPORT */ 1492 int bcm_esw_trident3_pstats_not_empty; 1493 #endif /* INCLUDE_PSTATS && BCM_TRIDENT3_SUPPORT */