switch.c (45799B)
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 * Module : Switch 8 * 9 * Purpose: 10 * Aggregation Monitor Management. 11 */ 12 13 #include <soc/defs.h> 14 #include <sal/core/libc.h> 15 16 #if defined(BCM_TOMAHAWK_SUPPORT) 17 #include <soc/drv.h> 18 #include <soc/scache.h> 19 #include <soc/debug.h> 20 #include <soc/tomahawk.h> 21 #include <soc/iproc.h> 22 23 #include <bcm/debug.h> 24 #include <bcm/error.h> 25 #include <bcm/time.h> 26 27 #include <bcm_int/esw/mbcm.h> 28 #include <bcm_int/esw/tomahawk.h> 29 #include <bcm_int/esw/switch.h> 30 #include <bcm_int/esw/flex_ctr.h> 31 #include <bcm_int/esw_dispatch.h> 32 33 /* Definitions */ 34 35 #define AGM_CHECK(unit, agm_id) \ 36 if ((agm_id) < AGM_CNTL(unit).agm_id_min || (agm_id) > AGM_CNTL(unit).agm_id_max) \ 37 { return BCM_E_PARAM; } 38 #define AGM_LOCK(unit) soc_mem_lock(unit, AGM_MONITOR_TABLEm) 39 #define AGM_UNLOCK(unit) soc_mem_unlock(unit, AGM_MONITOR_TABLEm) 40 41 /* Data structure */ 42 typedef struct agm_cntl_s { 43 int agm_id_min; 44 int agm_id_max; 45 int agm_period_max; 46 int agm_timer_id; 47 int agm_pool_conf[_AGM_POOL_ID_CNT]; 48 agm_monitor_t *agm_info; 49 } agm_cntl_t; 50 51 /* 52 * One agm control entry for each SOC device containing AGM book keeping 53 * info for that device. 54 */ 55 static agm_cntl_t bcm_agm_control[BCM_MAX_NUM_UNITS]; 56 57 #define AGM_CNTL(unit) bcm_agm_control[unit] 58 #define AGM_INFO(unit, aid) bcm_agm_control[unit].agm_info[(aid)] 59 60 /* 61 * Cause a routine to return BCM_E_INIT if agm subsystem is not 62 * initialized. 63 */ 64 #define AGM_INIT(unit) \ 65 if ( (AGM_CNTL(unit).agm_id_max <= 0) && \ 66 (AGM_CNTL(unit).agm_period_max <= 0) ) { return BCM_E_INIT; } 67 /* 68 * 0: ECMP1, ECMP2 69 * 1: ECMP1, TRUNK 70 * 2: ECMP1, HG-TRUNK 71 * 3: TRUNK, HG-TRUNK 72 */ 73 #define _POOL_EMPTY(unit, pid) \ 74 (AGM_CNTL(unit).agm_pool_conf[(pid)] == _AGM_POOL_ID_INVALID) 75 #define _POOL_CHECK(unit, pid, type) \ 76 (AGM_CNTL(unit).agm_pool_conf[(pid)] == (type)) 77 78 /* Functions */ 79 80 int 81 bcm_th_switch_agm_deinit(int unit) 82 { 83 if (AGM_CNTL(unit).agm_info != NULL) { 84 sal_free(AGM_CNTL(unit).agm_info); 85 } 86 sal_memset(&AGM_CNTL(unit), 0, sizeof(AGM_CNTL(unit))); 87 88 return BCM_E_NONE; 89 } 90 91 int 92 bcm_th_switch_agm_id_validate(int unit, bcm_switch_agm_id_t agm_id) { 93 AGM_INIT(unit); 94 AGM_CHECK(unit, agm_id); 95 return BCM_E_NONE; 96 } 97 98 int 99 _bcm_th_switch_agm_update_counter_id( 100 int unit, bcm_switch_agm_id_t agm_id, int counter_id) 101 { 102 int rv = BCM_E_NONE; 103 104 AGM_CHECK(unit, agm_id); 105 106 if (AGM_INFO(unit, agm_id).in_use) { 107 AGM_INFO(unit, agm_id).counter_id = counter_id; 108 } else { 109 rv = BCM_E_NOT_FOUND; 110 } 111 112 return rv; 113 } 114 115 int 116 _bcm_th_switch_agm_info(int unit, bcm_switch_agm_id_t agm_id, 117 agm_monitor_t *agm_mnt) 118 { 119 int rv = BCM_E_NONE; 120 121 if (AGM_INFO(unit, agm_id).in_use) { 122 sal_memcpy(agm_mnt, &AGM_INFO(unit, agm_id), sizeof(*agm_mnt)); 123 } else { 124 rv = BCM_E_NOT_FOUND; 125 } 126 127 return rv; 128 } 129 130 int 131 bcm_th_switch_agm_init(int unit) 132 { 133 int i, agm_alloc_sz; 134 135 soc_mem_t agm_tbl = AGM_MONITOR_TABLEm; 136 137 AGM_CNTL(unit).agm_id_min = soc_mem_index_min(unit, agm_tbl); 138 AGM_CNTL(unit).agm_id_max = soc_mem_index_max(unit, agm_tbl); 139 AGM_CNTL(unit).agm_period_max = (1 << soc_mem_field_length(unit, agm_tbl, 140 PERIOD_MAXf)) - 1; 141 AGM_CNTL(unit).agm_timer_id = _AGM_TIME_ID_INVALID; 142 for (i = 0; i < _AGM_POOL_ID_CNT; i++) { 143 AGM_CNTL(unit).agm_pool_conf[i] = _AGM_POOL_ID_INVALID; 144 } 145 146 if (AGM_CNTL(unit).agm_info != NULL) { 147 sal_free(AGM_CNTL(unit).agm_info); 148 AGM_CNTL(unit).agm_info = NULL; 149 } 150 151 agm_alloc_sz = (AGM_CNTL(unit).agm_id_max - AGM_CNTL(unit).agm_id_min + 1) * 152 sizeof(agm_monitor_t); 153 AGM_CNTL(unit).agm_info = sal_alloc(agm_alloc_sz, "agm_cntl.info"); 154 if (AGM_CNTL(unit).agm_info == NULL) { 155 return BCM_E_MEMORY; 156 } 157 sal_memset(AGM_CNTL(unit).agm_info, 0, agm_alloc_sz); 158 159 for (i = 0; i <= (AGM_CNTL(unit).agm_id_max - AGM_CNTL(unit).agm_id_min); 160 i++) { 161 AGM_INFO(unit, i).attr.agm_id = _AGM_ID_INVALID; 162 AGM_INFO(unit, i).group_id = _AGM_GROUP_ID_INVALID; 163 } 164 165 return BCM_E_NONE; 166 } 167 168 #if defined (BCM_WARM_BOOT_SUPPORT) 169 int 170 bcm_th_switch_tflow_wb_scache_size_get(int unit, int *req_scache_size) 171 { 172 int alloc_size = 0; 173 174 alloc_size += sizeof(_bcm_switch_tflow_mode_t); 175 *req_scache_size += alloc_size; 176 177 return BCM_E_NONE; 178 } 179 180 int 181 bcm_th_switch_tflow_wb_sync(int unit, uint8 **scache_ptr) 182 { 183 _bcm_switch_tflow_mode_t *tflow_scache_p; 184 185 tflow_scache_p = (_bcm_switch_tflow_mode_t *)(*scache_ptr); 186 187 sal_memcpy(tflow_scache_p, &(_bcm_switch_tflow_mode_info[unit]), sizeof(_bcm_switch_tflow_mode_t)); 188 tflow_scache_p++; 189 190 *scache_ptr = (uint8 *)tflow_scache_p; 191 192 return BCM_E_NONE; 193 } 194 195 int 196 bcm_th_switch_tflow_wb_reinit(int unit, uint8 **scache_ptr) 197 { 198 _bcm_switch_tflow_mode_t *tflow_scache_p; 199 200 tflow_scache_p = (_bcm_switch_tflow_mode_t *)(*scache_ptr); 201 202 sal_memcpy(&(_bcm_switch_tflow_mode_info[unit]), tflow_scache_p, sizeof(_bcm_switch_tflow_mode_t)); 203 tflow_scache_p++; 204 205 *scache_ptr = (uint8 *)tflow_scache_p; 206 207 return BCM_E_NONE; 208 } 209 210 211 int 212 bcm_th_switch_agm_wb_scache_size_get(int unit, int *req_scache_size) 213 { 214 int alloc_size = 0; 215 216 alloc_size += sizeof(agm_cntl_t); 217 alloc_size += ((AGM_CNTL(unit).agm_id_max - AGM_CNTL(unit).agm_id_min + 1) * 218 sizeof(agm_monitor_t)); 219 220 *req_scache_size += alloc_size; 221 222 return BCM_E_NONE; 223 } 224 225 int 226 bcm_th_switch_agm_wb_sync(int unit, uint8 **scache_ptr) 227 { 228 agm_cntl_t *agm_cntl_scache_p; 229 agm_monitor_t * agm_info_scache_p; 230 int agm_info_num; 231 232 agm_cntl_scache_p = (agm_cntl_t *)(*scache_ptr); 233 234 sal_memcpy(agm_cntl_scache_p, &AGM_CNTL(unit), sizeof(agm_cntl_t)); 235 agm_cntl_scache_p ++; 236 237 agm_info_scache_p = (agm_monitor_t *)agm_cntl_scache_p; 238 agm_info_num = AGM_CNTL(unit).agm_id_max - AGM_CNTL(unit).agm_id_min + 1; 239 sal_memcpy(agm_info_scache_p, AGM_CNTL(unit).agm_info, 240 agm_info_num * sizeof(agm_monitor_t)); 241 agm_info_scache_p += agm_info_num; 242 243 *scache_ptr = (uint8 *)agm_info_scache_p; 244 245 return BCM_E_NONE; 246 } 247 248 int 249 bcm_th_switch_agm_wb_reinit(int unit, uint8 **scache_ptr) 250 { 251 agm_cntl_t *agm_cntl_scache_p; 252 agm_monitor_t * agm_info_scache_p; 253 int agm_info_num; 254 255 agm_cntl_scache_p = (agm_cntl_t *)(*scache_ptr); 256 257 sal_memcpy(&AGM_CNTL(unit), agm_cntl_scache_p, sizeof(agm_cntl_t)); 258 agm_cntl_scache_p ++; 259 260 agm_info_scache_p = (agm_monitor_t *)agm_cntl_scache_p; 261 agm_info_num = AGM_CNTL(unit).agm_id_max - AGM_CNTL(unit).agm_id_min + 1; 262 AGM_CNTL(unit).agm_info = sal_alloc(agm_info_num * sizeof(agm_monitor_t), 263 "agm_cntl.info"); 264 if (AGM_CNTL(unit).agm_info == NULL) { 265 return BCM_E_MEMORY; 266 } 267 sal_memcpy(AGM_CNTL(unit).agm_info, agm_info_scache_p, 268 agm_info_num * sizeof(agm_monitor_t)); 269 agm_info_scache_p += agm_info_num; 270 271 *scache_ptr = (uint8 *)agm_info_scache_p; 272 273 return BCM_E_NONE; 274 } 275 #endif 276 277 int 278 bcm_th_switch_agm_dump(int unit) 279 { 280 /* For trouble-shooting */ 281 AGM_INIT(unit); 282 283 return BCM_E_NONE; 284 } 285 286 /* 287 * 0: ECMP, ECMP 288 * 1: ECMP, TRUNK 289 * 2: ECMP, HG-TRUNK 290 * 3: TRUNK, HG-TRUNK 291 */ 292 STATIC int 293 _th_agm_pool_alloc(int unit, bcm_switch_agm_type_t agm_type, int *pool_id) 294 { 295 int i; 296 297 for (i = 0; i < _AGM_POOL_ID_CNT; i++) { 298 if (_POOL_EMPTY(unit, i) || _POOL_CHECK(unit, i, agm_type)) { 299 *pool_id = i; 300 return BCM_E_NONE; 301 } 302 } 303 304 return BCM_E_FULL; 305 306 } 307 308 STATIC int 309 _th_agm_id_alloc(int unit, int *agm_id) 310 { 311 int i; 312 313 for (i = AGM_CNTL(unit).agm_id_min + 1; i <= AGM_CNTL(unit).agm_id_max; i++) { 314 if (AGM_INFO(unit, i).attr.agm_id != _AGM_ID_INVALID) { 315 continue; 316 } 317 *agm_id = i; 318 return BCM_E_NONE; 319 } 320 321 return BCM_E_FULL; 322 } 323 324 STATIC int 325 _th_agm_itvl2scale(int unit, bcm_switch_agm_period_interval_t itvl) 326 { 327 int scale = 0; 328 329 switch (itvl) { 330 case bcmSwitchAgmInterval1Second: 331 scale = 5; 332 break; 333 case bcmSwitchAgmInterval100MiliSecond: 334 scale = 4; 335 break; 336 case bcmSwtichAgmInterval10MiliSecond: 337 scale = 3; 338 break; 339 case bcmSwitchAgmInterval1MiliSecond: 340 scale = 2; 341 break; 342 case bcmSwitchAgmInterval100MacroSecond: 343 scale = 1; 344 break; 345 default: 346 break; 347 } 348 349 return scale; 350 } 351 352 /* Retrieve table info for AGM instance */ 353 int 354 bcm_th_agm_stat_get_table_info(int unit, bcm_switch_agm_id_t agm_id, 355 uint32 *num_of_tables, void *tbl_info) 356 { 357 int index = agm_id; 358 bcm_stat_flex_table_info_t *table_info = NULL; 359 360 (*num_of_tables) = 0; 361 if (!soc_feature(unit,soc_feature_advanced_flex_counter)) { 362 return BCM_E_UNAVAIL; 363 } 364 365 table_info = (bcm_stat_flex_table_info_t *) tbl_info; 366 table_info[*num_of_tables].table = AGM_MONITOR_TABLEm; 367 table_info[*num_of_tables].index = index; 368 table_info[*num_of_tables].direction = bcmStatFlexDirectionIngress; 369 (*num_of_tables)++; 370 371 return BCM_E_NONE; 372 } 373 374 /* Get counter id for accounnting table AGM */ 375 int 376 bcm_th_agm_stat_id_get(int unit, bcm_switch_agm_id_t agm_id, 377 int agm_pid, int total_cntr_idxs, uint32 *stat_counter_id) 378 { 379 int rv = BCM_E_NONE; 380 381 bcm_stat_group_mode_id_config_t stat_config; 382 bcm_stat_group_mode_attr_selector_t attr_sel[1]; 383 uint32 mode_id; 384 uint32 num_entries; 385 uint32 num_sel; 386 387 if (!soc_feature(unit,soc_feature_advanced_flex_counter)) { 388 return BCM_E_UNAVAIL; 389 } 390 391 bcm_stat_group_mode_id_config_t_init(&stat_config); 392 bcm_stat_group_mode_attr_selector_t_init(attr_sel); 393 394 stat_config.flags = BCM_STAT_GROUP_MODE_INGRESS; 395 stat_config.total_counters = total_cntr_idxs; 396 stat_config.hint.type = bcmIntStatGroupAllocHintIngressAgmGroup; 397 stat_config.hint.value = 1; 398 399 /* Create custom mode id with config */ 400 attr_sel[0].attr = 0; 401 attr_sel[0].attr_value = 0; 402 attr_sel[0].counter_offset = 0; 403 num_sel = 1; 404 rv = bcm_esw_stat_group_mode_id_config_create(unit, 0, &stat_config, 405 num_sel, attr_sel, &mode_id); 406 if (BCM_FAILURE(rv) && rv != BCM_E_EXISTS) { 407 return rv; 408 } 409 410 /* Create counter id */ 411 if (agm_pid) { 412 rv = bcm_esw_stat_custom_group_create(unit, mode_id, 413 (bcm_stat_object_t)bcmIntStatObjectIngAgmSecondLookup, 414 stat_counter_id, &num_entries); 415 } else { 416 rv = bcm_esw_stat_custom_group_create(unit, mode_id, 417 (bcm_stat_object_t)bcmIntStatObjectIngAgm, 418 stat_counter_id, &num_entries); 419 } 420 if (BCM_FAILURE(rv)) { 421 return rv; 422 } 423 424 /* Make sure there is space there */ 425 if (total_cntr_idxs > num_entries) { 426 BCM_IF_ERROR_RETURN(bcm_esw_stat_group_destroy(unit, *stat_counter_id)); 427 return BCM_E_RESOURCE; 428 } 429 430 return rv; 431 } 432 433 /* Destroy AGM counter id */ 434 int 435 bcm_th_agm_stat_id_clear(int unit, uint32 stat_counter_id) 436 { 437 bcm_stat_group_mode_t gmode; 438 bcm_stat_object_t stat_object; 439 uint32 mode, pool, base_idx; 440 int rv; 441 442 #if defined(BCM_TOMAHAWK3_SUPPORT) 443 if (SOC_IS_TOMAHAWK3(unit) && !stat_counter_id) { 444 return BCM_E_NONE; 445 } 446 #endif /* BCM_TOMAHAWK3_SUPPORT */ 447 448 _bcm_esw_stat_get_counter_id_info(unit, stat_counter_id, &gmode, 449 &stat_object, &mode, &pool, &base_idx); 450 451 BCM_IF_ERROR_RETURN(bcm_esw_stat_group_destroy(unit, stat_counter_id)); 452 453 /* This function could return BUSY if the reference count is non-zero */ 454 rv = _bcm_esw_stat_group_mode_id_destroy(unit, mode); 455 if (rv == BCM_E_BUSY) 456 return BCM_E_NONE; 457 return rv; 458 } 459 460 /* Detach Flex counter from AGM monitor */ 461 int 462 bcm_th_agm_stat_detach(int unit, 463 bcm_switch_agm_id_t agm_id, int agm_pid, uint32 ctr_id) 464 { 465 soc_mem_t table; 466 bcm_stat_flex_direction_t direction; 467 bcm_stat_object_t object; 468 uint32 count = 0; 469 uint32 actual_num_tables = 0; 470 uint32 num_of_tables = 0; 471 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 472 473 #if defined(BCM_TOMAHAWK3_SUPPORT) 474 if (SOC_IS_TOMAHAWK3(unit) && !ctr_id) { 475 return BCM_E_NONE; 476 } 477 #else 478 COMPILER_REFERENCE(ctr_id); 479 #endif /* BCM_TOMAHAWK3_SUPPORT */ 480 481 direction = bcmStatFlexDirectionIngress; 482 if (agm_pid) { 483 object = bcmIntStatObjectIngAgmSecondLookup; 484 } else { 485 object = bcmIntStatObjectIngAgm; 486 } 487 488 BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_object(unit, object, &direction)); 489 BCM_IF_ERROR_RETURN(_bcm_esw_stat_flex_get_table_info(unit, object, 1, 490 &actual_num_tables, &table, &direction)); 491 492 BCM_IF_ERROR_RETURN(bcm_th_agm_stat_get_table_info(unit, agm_id, 493 &num_of_tables, &table_info[0])); 494 for (count = 0; count < num_of_tables; count++) { 495 if ((table_info[count].direction == direction) && 496 (table_info[count].table == table)) { 497 if (direction == bcmStatFlexDirectionIngress) { 498 return _bcm_esw_stat_flex_detach_ingress_table_counters1( 499 unit, table_info[count].table, 500 table_info[count].index, object); 501 } else { 502 return _bcm_esw_stat_flex_detach_egress_table_counters( 503 unit, 0, table_info[count].table, 504 table_info[count].index); 505 } 506 } 507 } 508 509 return BCM_E_NOT_FOUND; 510 } 511 512 /* Attach a flex counter to AGM monitor */ 513 int 514 bcm_th_agm_stat_attach(int unit, bcm_switch_agm_id_t agm_id, 515 int agm_pid, uint32 counter_id) 516 { 517 soc_mem_t table; 518 bcm_stat_flex_direction_t direction; 519 uint32 pool_number = 0; 520 uint32 base_index = 0; 521 bcm_stat_flex_mode_t offset_mode = 0; 522 bcm_stat_object_t object; 523 bcm_stat_group_mode_t group_mode; 524 uint32 count = 0; 525 uint32 actual_num_tables = 0; 526 uint32 num_of_tables = 0; 527 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 528 529 direction = bcmStatFlexDirectionIngress; 530 if (agm_pid) { 531 object = bcmIntStatObjectIngAgmSecondLookup; 532 } else { 533 object = bcmIntStatObjectIngAgm; 534 } 535 group_mode = bcmStatGroupModeSingle; 536 537 _bcm_esw_stat_get_counter_id_info(unit, counter_id, &group_mode, &object, 538 &offset_mode, &pool_number, &base_index); 539 BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_object(unit, object, &direction)); 540 BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_group(unit, group_mode)); 541 BCM_IF_ERROR_RETURN(_bcm_esw_stat_flex_get_table_info(unit, object, 1, 542 &actual_num_tables, &table, &direction)); 543 544 BCM_IF_ERROR_RETURN(bcm_th_agm_stat_get_table_info(unit, agm_id, 545 &num_of_tables, &table_info[0])); 546 for (count = 0; count < num_of_tables ; count++) { 547 if ((table_info[count].direction == direction) && 548 (table_info[count].table == table)) { 549 if (direction == bcmStatFlexDirectionIngress) { 550 return _bcm_esw_stat_flex_attach_ingress_table_counters2( 551 unit, table_info[count].table, 552 table_info[count].index, offset_mode, base_index, 553 pool_number, object, NULL); 554 } else { 555 return _bcm_esw_stat_flex_attach_egress_table_counters( 556 unit, table_info[count].table, 557 table_info[count].index, 0, offset_mode, base_index, 558 pool_number); 559 } 560 } 561 } 562 563 return BCM_E_NOT_FOUND; 564 } 565 566 /* Fill trunk member to AGM stat array */ 567 STATIC int 568 _th_agm_trunk_member_fill(int unit, bcm_switch_agm_id_t agm_id, 569 bcm_trunk_t tid, int nstat, 570 bcm_switch_agm_stat_t *stat_arr) 571 { 572 int i, rv = BCM_E_NONE; 573 bcm_trunk_info_t tinfo; 574 int mbm_cnt, mbm_max; 575 bcm_trunk_member_t *mbm_arr; 576 577 mbm_max = AGM_INFO(unit, agm_id).attr.num_members; 578 mbm_arr = sal_alloc(mbm_max * sizeof(*mbm_arr), "mbm_arr"); 579 if (mbm_arr == NULL) { 580 return BCM_E_MEMORY; 581 } 582 583 rv = bcm_esw_trunk_get(unit, tid, &tinfo, mbm_max, mbm_arr, &mbm_cnt); 584 if (BCM_FAILURE(rv)) { 585 sal_free(mbm_arr); 586 return rv; 587 } 588 589 if (mbm_cnt == 0) { 590 sal_free(mbm_arr); 591 return BCM_E_FAIL; 592 } 593 594 /* Could cross multi monitor period */ 595 for (i = 0; i < nstat; i++) { 596 stat_arr[i].intf_id = BCM_IF_INVALID; 597 stat_arr[i].gport_id = mbm_arr[i % mbm_cnt].gport; 598 } 599 600 sal_free(mbm_arr); 601 602 return BCM_E_NONE; 603 604 } 605 606 #if defined(INCLUDE_L3) 607 /* Fill l3 ecmp member to AGM stat array */ 608 STATIC int 609 _th_agm_l3_ecmp_member_fill(int unit, bcm_switch_agm_id_t agm_id, 610 bcm_if_t l3_ecmp_id, int nstat, 611 bcm_switch_agm_stat_t *stat_arr) 612 { 613 int i, rv = BCM_E_NONE; 614 int mbm_cnt = 0, mbm_max; 615 bcm_if_t *mbm_arr; 616 617 mbm_max = AGM_INFO(unit, agm_id).attr.num_members; 618 mbm_arr = sal_alloc(mbm_max * sizeof(*mbm_arr), "mbm_arr"); 619 if (mbm_arr == NULL) { 620 return BCM_E_MEMORY; 621 } 622 623 rv = bcm_esw_l3_egress_multipath_get(unit, l3_ecmp_id, mbm_max, 624 mbm_arr, &mbm_cnt); 625 if (BCM_FAILURE(rv)) { 626 sal_free(mbm_arr); 627 return rv; 628 } 629 630 if (mbm_cnt == 0) { 631 sal_free(mbm_arr); 632 return BCM_E_FAIL; 633 } 634 635 /* Could cross multi monitor period */ 636 for (i = 0; i < nstat; i++) { 637 stat_arr[i].gport_id = BCM_GPORT_INVALID; 638 stat_arr[i].intf_id = mbm_arr[i % mbm_cnt]; 639 } 640 641 sal_free(mbm_arr); 642 643 return BCM_E_NONE; 644 645 } 646 #endif 647 648 /* 649 * Function: 650 * bcm_th_switch_agm_create 651 * Purpose: 652 * Creates an aggregation monitoring entry which collects bandwidth and 653 * packet distribution information among members of a trunk group or 654 * an ecmp group. 655 */ 656 int 657 bcm_th_switch_agm_create(int unit, 658 uint32 options, 659 bcm_switch_agm_info_t *agm_info) 660 { 661 int rv = BCM_E_NONE; 662 int agm_pid, agm_id; 663 agm_monitor_table_entry_t entry; 664 uint32 counter_id = 0; 665 agm_monitor_t *agm_mng; 666 int scale; 667 668 /* Validate parameters */ 669 if (!SOC_UNIT_VALID(unit)) { 670 return BCM_E_UNIT; 671 } 672 673 AGM_INIT(unit); 674 675 if (agm_info == NULL) { 676 return BCM_E_PARAM; 677 } 678 679 if (agm_info->period_interval < bcmSwitchAgmInterval1Second || 680 agm_info->period_interval >= bcmSwitchAgmIntervalCount) { 681 LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit, 682 "Invalid period interval %d\n"), agm_info->period_interval)); 683 return BCM_E_PARAM; 684 } 685 686 if (agm_info->period_num < 0 || 687 agm_info->period_num > AGM_CNTL(unit).agm_period_max) { 688 LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit, 689 "Invalid period number %d\n"), agm_info->period_num)); 690 return BCM_E_PARAM; 691 } 692 693 #if defined(BCM_TOMAHAWK3_SUPPORT) 694 if (SOC_IS_TOMAHAWK3(unit)) { 695 if(bcmSwitchAgmTypeFabricTrunk == agm_info->agm_type) { 696 return BCM_E_PARAM; 697 } 698 if (agm_info->num_members <= 0) { 699 return BCM_E_PARAM; 700 } 701 } 702 #endif 703 704 AGM_LOCK(unit); 705 706 /* Check available agm pool */ 707 rv = _th_agm_pool_alloc(unit, agm_info->agm_type, &agm_pid); 708 if (BCM_FAILURE(rv)) { 709 AGM_UNLOCK(unit); 710 return rv; 711 } 712 713 /* Alloc monitor id */ 714 rv = _th_agm_id_alloc(unit, &agm_id); 715 if (BCM_FAILURE(rv)) { 716 AGM_UNLOCK(unit); 717 return rv; 718 } 719 720 LOG_VERBOSE(BSL_LS_BCM_SWITCH, (BSL_META_U(unit, 721 "Allocated AGM pool id %d, monitor id %d\n"), agm_pid, agm_id)); 722 723 #if defined(BCM_TOMAHAWK3_SUPPORT) 724 /* For TH3, skip creating Flex Stat counters for ECMP 725 * AGMs as it will be taken care at ECMP attach phase. 726 */ 727 if ((!SOC_IS_TOMAHAWK3(unit)) || 728 (bcmSwitchAgmTypeL3Ecmp != agm_info->agm_type && 729 bcmSwitchAgmTypeL3EcmpOverlay != agm_info->agm_type)) 730 #endif /* BCM_TOMAHAWK3_SUPPORT */ 731 { 732 733 rv = bcm_th_agm_stat_id_get(unit, 734 agm_id, 735 agm_pid, 736 agm_info->num_members * (agm_info->period_num + 1), 737 &counter_id); 738 if (BCM_FAILURE(rv)) { 739 AGM_UNLOCK(unit); 740 return rv; 741 } 742 743 LOG_VERBOSE(BSL_LS_BCM_SWITCH, (BSL_META_U(unit, 744 "Allocated counter id %d for AGM accouting table\n"), counter_id)); 745 746 rv = bcm_th_agm_stat_attach(unit, agm_id, agm_pid, counter_id); 747 if (BCM_FAILURE(rv)) { 748 bcm_th_agm_stat_id_clear(unit, counter_id); 749 AGM_UNLOCK(unit); 750 return rv; 751 } 752 753 LOG_VERBOSE(BSL_LS_BCM_SWITCH, (BSL_META_U(unit, 754 "Attached counter id %d to AGM %d\n"), counter_id, agm_id)); 755 } 756 757 rv = READ_AGM_MONITOR_TABLEm(unit, MEM_BLOCK_ANY, agm_id, &entry); 758 if (BCM_FAILURE(rv)) { 759 (void)bcm_th_agm_stat_detach(unit, agm_id, agm_pid, counter_id); 760 (void)bcm_th_agm_stat_id_clear(unit, counter_id); 761 AGM_UNLOCK(unit); 762 return rv; 763 } 764 765 /* For unlimited period, we need to set SCALE to 0 */ 766 if (agm_info->period_num == 0) { 767 scale = 0; 768 } else { 769 scale = _th_agm_itvl2scale(unit, agm_info->period_interval); 770 } 771 soc_mem_field32_set(unit, AGM_MONITOR_TABLEm, &entry, SCALEf, scale); 772 soc_mem_field32_set(unit, AGM_MONITOR_TABLEm, &entry, PERIOD_MAXf, 773 agm_info->period_num); 774 rv = WRITE_AGM_MONITOR_TABLEm(unit, MEM_BLOCK_ANY, agm_id, &entry); 775 if (BCM_FAILURE(rv)) { 776 (void)bcm_th_agm_stat_detach(unit, agm_id, agm_pid, counter_id); 777 (void)bcm_th_agm_stat_id_clear(unit, counter_id); 778 AGM_UNLOCK(unit); 779 return rv; 780 } 781 782 /* Update software bookkeeping information */ 783 AGM_CNTL(unit).agm_pool_conf[agm_pid] = agm_info->agm_type; 784 agm_mng = &AGM_INFO(unit, agm_id); 785 agm_mng->in_use = TRUE; 786 agm_mng->agm_pool_id = agm_pid; 787 agm_mng->counter_id = counter_id; 788 789 sal_memcpy(&agm_mng->attr, agm_info, sizeof(*agm_info)); 790 agm_mng->attr.agm_id = agm_id; 791 agm_info->agm_id = agm_id; 792 793 AGM_UNLOCK(unit); 794 return rv; 795 } 796 797 /* 798 * Function: 799 * bcm_esw_switch_agm_enable_set 800 * Purpose: 801 * Enable or disable the aggregation group monitoring. 802 */ 803 int 804 bcm_th_switch_agm_enable_set(int unit, 805 bcm_switch_agm_id_t agm_id, 806 int enable) 807 { 808 int i, rv = BCM_E_NONE; 809 agm_monitor_table_entry_t entry; 810 uint32 start_ts[2] = {0}; 811 bcm_time_interface_t time_intf; 812 813 /* Validate parameters */ 814 if (!SOC_UNIT_VALID(unit)) { 815 return BCM_E_UNIT; 816 } 817 818 AGM_INIT(unit); 819 AGM_CHECK(unit, agm_id); 820 821 AGM_LOCK(unit); 822 if (!AGM_INFO(unit, agm_id).in_use) { 823 AGM_UNLOCK(unit); 824 return BCM_E_NOT_FOUND; 825 } 826 827 /* Reentry check */ 828 if ((enable && AGM_INFO(unit, agm_id).running) || 829 (!enable && !AGM_INFO(unit, agm_id).running)) { 830 AGM_UNLOCK(unit); 831 return BCM_E_NONE; 832 } 833 834 /* Enable timer for the first time */ 835 if (enable && 836 AGM_INFO(unit, agm_id).attr.period_num > 0) { 837 time_intf.id = _AGM_TIME_ID_DFLT; 838 839 if (AGM_CNTL(unit).agm_timer_id == _AGM_TIME_ID_INVALID) { 840 time_intf.flags = BCM_TIME_ENABLE | BCM_TIME_WITH_ID; 841 sal_memset(&time_intf.drift, 0, sizeof(time_intf.drift)); 842 sal_memset(&time_intf.offset, 0, sizeof(time_intf.offset)); 843 sal_memset(&time_intf.accuracy, 0, sizeof(time_intf.accuracy)); 844 time_intf.heartbeat_hz = 4000; 845 time_intf.clk_resolution = 0; 846 time_intf.bitclock_hz = 10000000; 847 848 rv = bcm_esw_time_interface_add(unit, &time_intf); 849 if (BCM_FAILURE(rv) && rv != BCM_E_EXISTS) { 850 AGM_UNLOCK(unit); 851 return rv; 852 } 853 854 AGM_CNTL(unit).agm_timer_id = _AGM_TIME_ID_DFLT; 855 856 LOG_VERBOSE(BSL_LS_BCM_SWITCH, (BSL_META_U(unit, 857 "Created a time interface id %d for AGM %d.\n"), 858 AGM_CNTL(unit).agm_timer_id, agm_id));\ 859 } 860 861 #if defined(BCM_TOMAHAWK3_SUPPORT) 862 if (SOC_IS_TOMAHAWK3(unit)) { 863 READ_NS_TIMESYNC_TS0_TIMESTAMP_UPPER_STATUSr(unit, &start_ts[1]); 864 READ_NS_TIMESYNC_TS0_TIMESTAMP_LOWER_STATUSr(unit, &start_ts[0]); 865 READ_NS_TIMESYNC_TS0_TIMESTAMP_UPPER_STATUSr(unit, &start_ts[1]); 866 start_ts[0] = 867 (start_ts[0] >> 4 & 0x0FFFFFFF) | ((start_ts[1] & 0xF) << 28); 868 start_ts[1] >>= 4; 869 } else 870 #endif 871 { 872 bcm_time_capture_t time1; 873 bcm_time_capture_t_init(&time1); 874 (void) bcm_esw_time_capture_get(unit, time_intf.id, &time1); 875 876 READ_CMIC_TIMESYNC_INPUT_TIME_FIFO_TS_UPPERr(unit, &start_ts[1]); 877 READ_CMIC_TIMESYNC_INPUT_TIME_FIFO_TS_LOWERr(unit, &start_ts[0]); 878 } 879 } else if (!enable || AGM_INFO(unit, agm_id).attr.period_num <= 0) { 880 start_ts[0] = 0; 881 start_ts[1] = 0; 882 } 883 884 LOG_VERBOSE(BSL_LS_BCM_SWITCH, (BSL_META_U(unit, 885 "Start time stamp 0x%x_0x%x for AGM %d.\n"), start_ts[1], 886 start_ts[0], agm_id)); 887 888 /* Update to AGM monitor table */ 889 rv = READ_AGM_MONITOR_TABLEm(unit, MEM_BLOCK_ANY, agm_id, &entry); 890 if (BCM_FAILURE(rv)) { 891 AGM_UNLOCK(unit); 892 return rv; 893 } 894 895 soc_mem_field_set(unit, AGM_MONITOR_TABLEm, (uint32 *)&entry, 896 START_TIMESTAMPf, start_ts); 897 soc_mem_field32_set(unit, AGM_MONITOR_TABLEm, &entry, ENABLEf, enable); 898 rv = WRITE_AGM_MONITOR_TABLEm(unit, MEM_BLOCK_ANY, agm_id, &entry); 899 if (BCM_FAILURE(rv)) { 900 AGM_UNLOCK(unit); 901 return rv; 902 } 903 904 /* Update running state */ 905 AGM_INFO(unit, agm_id).running = enable ? TRUE : FALSE; 906 907 /* Destroy time interface if all monitors disabled. */ 908 if (!enable && AGM_CNTL(unit).agm_timer_id != _AGM_TIME_ID_INVALID) { 909 for (i = AGM_CNTL(unit).agm_id_min; 910 i <= AGM_CNTL(unit).agm_id_max; i++) { 911 if (AGM_INFO(unit, i).running) { 912 break; 913 } 914 } 915 916 /* All AGM instances are not running, remove time interface. */ 917 if (i > AGM_CNTL(unit).agm_id_max) { 918 rv = bcm_esw_time_interface_delete(unit, AGM_CNTL(unit).agm_timer_id); 919 if (BCM_FAILURE(rv) && rv != BCM_E_NOT_FOUND) { 920 AGM_UNLOCK(unit); 921 return rv; 922 } 923 924 LOG_VERBOSE(BSL_LS_BCM_SWITCH, (BSL_META_U(unit, 925 "All AGM monitor are stopped, delete time interface.\n"))); 926 927 AGM_CNTL(unit).agm_timer_id = _AGM_TIME_ID_INVALID; 928 } 929 } 930 931 AGM_UNLOCK(unit); 932 return rv; 933 } 934 935 /* 936 * Function: 937 * bcm_esw_switch_agm_stat_get 938 * Purpose: 939 * Retrieve bandwidth and packet distribution information that were 940 * collected via aggregation group monitoring 941 */ 942 int 943 bcm_th_switch_agm_stat_get(int unit, 944 bcm_switch_agm_id_t agm_id, 945 int nstat, 946 bcm_switch_agm_stat_t *stat_arr) 947 { 948 int i, rv = BCM_E_NONE; 949 int group_size; 950 uint32 *counter_indexes = NULL; 951 bcm_stat_value_t *counter_values = NULL; 952 bcm_switch_agm_type_t agm_type; 953 954 uint32 num_of_tables = 0; 955 int sync_mode = TRUE; 956 int byte_flag; 957 bcm_stat_flex_direction_t direction = bcmStatFlexDirectionIngress; 958 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 959 960 /* Validate parameters */ 961 if (!SOC_UNIT_VALID(unit)) { 962 return BCM_E_UNIT; 963 } 964 965 if (stat_arr == NULL) { 966 return BCM_E_PARAM; 967 } 968 969 AGM_INIT(unit); 970 AGM_CHECK(unit, agm_id); 971 972 AGM_LOCK(unit); 973 974 if (!AGM_INFO(unit, agm_id).in_use) { 975 AGM_UNLOCK(unit); 976 return BCM_E_NOT_FOUND; 977 } 978 979 counter_indexes = sal_alloc(sizeof(uint32) * nstat, "cntidx"); 980 if (counter_indexes == NULL) { 981 AGM_UNLOCK(unit); 982 return BCM_E_MEMORY; 983 } 984 counter_values = sal_alloc(sizeof(bcm_stat_value_t) * nstat, "cntval"); 985 if (counter_values == NULL) { 986 sal_free(counter_indexes); 987 AGM_UNLOCK(unit); 988 return BCM_E_MEMORY; 989 } 990 991 group_size = AGM_INFO(unit, agm_id).attr.num_members; 992 for (i = 0; i < nstat; i++) { 993 counter_indexes[i] = i; 994 stat_arr[i].period = i / group_size; 995 } 996 sal_memset(counter_values, 0, sizeof(bcm_stat_value_t) * nstat); 997 998 LOG_VERBOSE(BSL_LS_BCM_SWITCH, (BSL_META_U(unit, 999 "AGM %d stat get: group member count %d, period %d.\n"), agm_id, 1000 group_size, (nstat / group_size) + 1 )); 1001 1002 rv = bcm_th_agm_stat_get_table_info( 1003 unit, agm_id, &num_of_tables, &table_info[0]); 1004 if (BCM_FAILURE(rv)) { 1005 goto _free_exit; 1006 } 1007 1008 if (table_info[0].direction == direction) { 1009 /* Collect packet counters */ 1010 byte_flag = 0; 1011 for (i = 0; i < nstat; i++) { 1012 rv = _bcm_esw_stat_counter_get(unit, sync_mode, table_info[0].index, 1013 table_info[0].table, 0, byte_flag, counter_indexes[i], 1014 &counter_values[i]); 1015 if (BCM_FAILURE(rv)) { 1016 LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit, 1017 "AGM %d collected packet counter %d failed, rv = %d.\n"), 1018 agm_id, i, rv)); 1019 goto _free_exit; 1020 } 1021 stat_arr[i].packets = counter_values[i].packets64; 1022 } 1023 1024 /* Collect byte counters */ 1025 byte_flag = 1; 1026 for (i = 0; i < nstat; i++) { 1027 rv = _bcm_esw_stat_counter_get(unit, sync_mode, table_info[0].index, 1028 table_info[0].table, 0, byte_flag, counter_indexes[i], 1029 &counter_values[i]); 1030 if (BCM_FAILURE(rv)) { 1031 LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit, 1032 "AGM %d collected byte counter %d failed, rv = %d.\n"), 1033 agm_id, i, rv)); 1034 goto _free_exit; 1035 } 1036 stat_arr[i].bytes = counter_values[i].bytes; 1037 } 1038 } 1039 1040 /* Convert to agm_stat_attr */ 1041 agm_type = AGM_INFO(unit, agm_id).attr.agm_type; 1042 if (agm_type == bcmSwitchAgmTypeTrunk || 1043 agm_type == bcmSwitchAgmTypeFabricTrunk) { 1044 rv = _th_agm_trunk_member_fill(unit, agm_id, 1045 (bcm_trunk_t)AGM_INFO(unit, agm_id).group_id, 1046 nstat, stat_arr); 1047 } else if ((agm_type == bcmSwitchAgmTypeL3Ecmp) || 1048 (agm_type == bcmSwitchAgmTypeL3EcmpOverlay)) { 1049 #if defined(INCLUDE_L3) 1050 if (soc_feature(unit, soc_feature_l3)) { 1051 rv = _th_agm_l3_ecmp_member_fill(unit, agm_id, 1052 (bcm_if_t)AGM_INFO(unit, agm_id).group_id, 1053 nstat, stat_arr); 1054 } else 1055 #endif 1056 rv = BCM_E_UNAVAIL; 1057 } 1058 1059 if (BCM_FAILURE(rv)) { 1060 LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit, 1061 "AGM %d group member fill failed, group_id %d, rv = %d.\n"), agm_id, 1062 AGM_INFO(unit, agm_id).group_id, rv)); 1063 } 1064 1065 _free_exit: 1066 AGM_UNLOCK(unit); 1067 if (counter_indexes) { 1068 sal_free(counter_indexes); 1069 } 1070 1071 if (counter_values) { 1072 sal_free(counter_values); 1073 } 1074 1075 return rv; 1076 } 1077 1078 /* 1079 * Function: 1080 * bcm_esw_switch_agm_stat_clear 1081 * Purpose: 1082 * Clear stats of counter entries attached to the aggregation monitor (id) 1083 */ 1084 int 1085 bcm_th_switch_agm_stat_clear(int unit, bcm_switch_agm_id_t agm_id) 1086 { 1087 int i, rv = BCM_E_NONE; 1088 int group_size, group_num; 1089 uint32 *counter_indexes = NULL; 1090 bcm_stat_value_t *counter_values = NULL; 1091 int nstat; 1092 1093 uint32 num_of_tables = 0; 1094 int byte_flag; 1095 bcm_stat_flex_direction_t direction = bcmStatFlexDirectionIngress; 1096 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 1097 1098 /* Validate parameters */ 1099 if (!SOC_UNIT_VALID(unit)) { 1100 return BCM_E_UNIT; 1101 } 1102 1103 AGM_INIT(unit); 1104 AGM_CHECK(unit, agm_id); 1105 1106 AGM_LOCK(unit); 1107 if (!AGM_INFO(unit, agm_id).in_use) { 1108 AGM_UNLOCK(unit); 1109 return BCM_E_NOT_FOUND; 1110 } 1111 1112 group_size = AGM_INFO(unit, agm_id).attr.num_members; 1113 group_num = AGM_INFO(unit, agm_id).attr.period_num; 1114 nstat = group_size * (group_num + 1); 1115 AGM_UNLOCK(unit); 1116 1117 counter_indexes = sal_alloc(sizeof(uint32) * nstat, "cntidx"); 1118 if (counter_indexes == NULL) { 1119 return BCM_E_MEMORY; 1120 } 1121 counter_values = sal_alloc(sizeof(bcm_stat_value_t) * nstat, "cntval"); 1122 if (counter_values == NULL) { 1123 sal_free(counter_indexes); 1124 return BCM_E_MEMORY; 1125 } 1126 1127 for (i = 0; i < nstat; i++) { 1128 counter_indexes[i] = i; 1129 } 1130 sal_memset(counter_values, 0, sizeof(bcm_stat_value_t) * nstat); 1131 1132 rv = bcm_th_agm_stat_get_table_info( 1133 unit, agm_id, &num_of_tables, &table_info[0]); 1134 if (rv < 0) { 1135 goto _free_exit; 1136 } 1137 1138 if (table_info[0].direction == direction) { 1139 /* Clear packet counters */ 1140 byte_flag = 0; 1141 for (i = 0; i < nstat; i++) { 1142 rv = _bcm_esw_stat_counter_set(unit, table_info[0].index, 1143 table_info[0].table, 0, byte_flag, counter_indexes[i], 1144 &counter_values[i]); 1145 if (BCM_FAILURE(rv)) { 1146 LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit, 1147 "AGM %d clear packet counter %d failed, rv = %d.\n"), 1148 agm_id, i, rv)); 1149 goto _free_exit; 1150 } 1151 } 1152 1153 /* Clear byte counters */ 1154 byte_flag = 1; 1155 for (i = 0; i < nstat; i++) { 1156 rv = _bcm_esw_stat_counter_set(unit, table_info[0].index, 1157 table_info[0].table, 0, byte_flag, counter_indexes[i], 1158 &counter_values[i]); 1159 if (BCM_FAILURE(rv)) { 1160 LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit, 1161 "AGM %d clear byte counter %d failed, rv = %d.\n"), 1162 agm_id, i, rv)); 1163 goto _free_exit; 1164 } 1165 } 1166 } 1167 1168 _free_exit: 1169 if (counter_indexes) { 1170 sal_free(counter_indexes); 1171 } 1172 1173 if (counter_values) { 1174 sal_free(counter_values); 1175 } 1176 1177 return rv; 1178 } 1179 1180 /* 1181 * Function: 1182 * bcm_esw_switch_agm_destroy 1183 * Purpose: 1184 * Destroy an existing aggregation monitoring entry 1185 */ 1186 int 1187 bcm_th_switch_agm_destroy(int unit, bcm_switch_agm_id_t agm_id) 1188 { 1189 int i, rv = BCM_E_NONE; 1190 agm_monitor_t *agm_mnt; 1191 int pool_id; 1192 1193 /* Validate parameters */ 1194 if (!SOC_UNIT_VALID(unit)) { 1195 return BCM_E_UNIT; 1196 } 1197 1198 AGM_INIT(unit); 1199 AGM_CHECK(unit, agm_id); 1200 1201 agm_mnt = &AGM_INFO(unit, agm_id); 1202 if (agm_mnt->attr.agm_id == _AGM_ID_INVALID) { 1203 return BCM_E_NOT_FOUND; 1204 } 1205 1206 /* Disable running AGM */ 1207 AGM_LOCK(unit); 1208 if (!agm_mnt->in_use) { 1209 AGM_UNLOCK(unit); 1210 return BCM_E_NOT_FOUND; 1211 } 1212 1213 if (agm_mnt->in_use && agm_mnt->group_id != _AGM_GROUP_ID_INVALID) { 1214 LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit, 1215 "AGM %d is attached need to detach first\n"), agm_id)); 1216 return BCM_E_BUSY; 1217 } 1218 1219 if (agm_mnt->running) { 1220 rv = bcm_th_switch_agm_enable_set(unit, agm_id, FALSE); 1221 if (BCM_FAILURE(rv)) { 1222 AGM_UNLOCK(unit); 1223 LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit, 1224 "AGM %d disable failed, rv = %d.\n"), agm_id, rv)); 1225 return rv; 1226 } 1227 } 1228 1229 /* Destory flex counter */ 1230 rv = bcm_th_agm_stat_detach(unit, agm_mnt->attr.agm_id, 1231 agm_mnt->agm_pool_id, (uint32)agm_mnt->counter_id); 1232 if (BCM_FAILURE(rv)) { 1233 AGM_UNLOCK(unit); 1234 LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit, 1235 "AGM %d detach failed, rv = %d.\n"), agm_id, rv)); 1236 return rv; 1237 } 1238 1239 rv = bcm_th_agm_stat_id_clear(unit, agm_mnt->counter_id); 1240 if (BCM_FAILURE(rv)) { 1241 AGM_UNLOCK(unit); 1242 LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit, 1243 "AGM %d destroy counter id failed, rv = %d.\n"), agm_id, rv)); 1244 return rv; 1245 } 1246 1247 /* Restore AGM bookeeping info to default value */ 1248 pool_id = agm_mnt->agm_pool_id; 1249 agm_mnt->in_use = FALSE; 1250 agm_mnt->running = FALSE; 1251 agm_mnt->agm_pool_id = _AGM_POOL_ID_INVALID; 1252 agm_mnt->group_id = _AGM_GROUP_ID_INVALID; 1253 agm_mnt->counter_id = 0; 1254 sal_memset(&agm_mnt->attr, 0, sizeof(agm_mnt->attr)); 1255 agm_mnt->attr.agm_id = _AGM_ID_INVALID; 1256 1257 rv = WRITE_AGM_MONITOR_TABLEm(unit, MEM_BLOCK_ANY, agm_id, 1258 soc_mem_entry_null(unit, AGM_MONITOR_TABLEm)); 1259 if (BCM_SUCCESS(rv)) { 1260 /* Using ref_cnt? */ 1261 for (i = AGM_CNTL(unit).agm_id_min; i <= AGM_CNTL(unit).agm_id_max; i++) { 1262 if (AGM_INFO(unit, i).in_use && 1263 AGM_INFO(unit, i).agm_pool_id == pool_id) { 1264 break; 1265 } 1266 } 1267 1268 /* Free pool_id if nobody use it */ 1269 if (i > AGM_CNTL(unit).agm_id_max) { 1270 AGM_CNTL(unit).agm_pool_conf[pool_id] = _AGM_POOL_ID_INVALID; 1271 } 1272 } 1273 1274 AGM_UNLOCK(unit); 1275 return rv; 1276 } 1277 1278 /* 1279 * Function: 1280 * bcm_esw_switch_agm_trunk_attach_get 1281 * Purpose: 1282 * Retrieve a (fabric) trunk_id where the monitor entry is attached 1283 */ 1284 int 1285 bcm_th_switch_agm_trunk_attach_get(int unit, bcm_switch_agm_id_t agm_id, 1286 bcm_trunk_t *trunk_id) 1287 { 1288 int rv = BCM_E_NONE; 1289 1290 /* Validate parameters */ 1291 if (!SOC_UNIT_VALID(unit)) { 1292 return BCM_E_UNIT; 1293 } 1294 1295 if (trunk_id == NULL) { 1296 return BCM_E_PARAM; 1297 } 1298 1299 AGM_INIT(unit); 1300 AGM_CHECK(unit, agm_id); 1301 1302 AGM_LOCK(unit); 1303 1304 if (!AGM_INFO(unit, agm_id).in_use || 1305 AGM_INFO(unit, agm_id).group_id == _AGM_GROUP_ID_INVALID || 1306 (AGM_INFO(unit, agm_id).attr.agm_type != bcmSwitchAgmTypeTrunk && 1307 AGM_INFO(unit, agm_id).attr.agm_type != bcmSwitchAgmTypeFabricTrunk) 1308 ){ 1309 AGM_UNLOCK(unit); 1310 LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit, 1311 "AGM %d trunk attach not found\n"), agm_id)); 1312 return BCM_E_NOT_FOUND; 1313 } 1314 1315 *trunk_id = (bcm_trunk_t)AGM_INFO(unit, agm_id).group_id; 1316 1317 AGM_UNLOCK(unit); 1318 1319 return rv; 1320 } 1321 1322 /* 1323 * Function: 1324 * bcm_esw_switch_agm_l3_ecmp_attach_get 1325 * Purpose: 1326 * Retrieve a l3 ecmp group id where the monitor entry is attached 1327 */ 1328 int 1329 bcm_th_switch_agm_l3_ecmp_attach_get(int unit, bcm_switch_agm_id_t agm_id, 1330 bcm_if_t *l3_ecmp_id) 1331 { 1332 int rv = BCM_E_NONE; 1333 1334 /* Validate parameters */ 1335 if (!SOC_UNIT_VALID(unit)) { 1336 return BCM_E_UNIT; 1337 } 1338 1339 if (l3_ecmp_id == NULL) { 1340 return BCM_E_PARAM; 1341 } 1342 1343 AGM_INIT(unit); 1344 AGM_CHECK(unit, agm_id); 1345 1346 AGM_LOCK(unit); 1347 if (!AGM_INFO(unit, agm_id).in_use || 1348 AGM_INFO(unit, agm_id).group_id == _AGM_GROUP_ID_INVALID || 1349 ((AGM_INFO(unit, agm_id).attr.agm_type != bcmSwitchAgmTypeL3Ecmp) && 1350 (AGM_INFO(unit, agm_id).attr.agm_type != bcmSwitchAgmTypeL3EcmpOverlay))) { 1351 AGM_UNLOCK(unit); 1352 LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit, 1353 "AGM %d l3 ecmp attach not found\n"), agm_id)); 1354 return BCM_E_NOT_FOUND; 1355 } 1356 1357 *l3_ecmp_id = (bcm_if_t)AGM_INFO(unit, agm_id).group_id; 1358 1359 AGM_UNLOCK(unit); 1360 1361 return rv; 1362 } 1363 1364 /* 1365 * Function: 1366 * bcm_esw_switch_agm_get 1367 * Purpose: 1368 * Retrieve the AGM monitor info of the specified AGM id. 1369 */ 1370 int 1371 bcm_th_switch_agm_get(int unit, bcm_switch_agm_info_t *agm_info) 1372 { 1373 int rv = BCM_E_NONE; 1374 bcm_switch_agm_id_t agm_id; 1375 1376 /* Validate parameters */ 1377 if (!SOC_UNIT_VALID(unit)) { 1378 return BCM_E_UNIT; 1379 } 1380 1381 if (agm_info == NULL) { 1382 return BCM_E_PARAM; 1383 } 1384 1385 AGM_INIT(unit); 1386 agm_id = agm_info->agm_id; 1387 AGM_CHECK(unit, agm_id); 1388 1389 AGM_LOCK(unit); 1390 if (!AGM_INFO(unit, agm_id).in_use) { 1391 AGM_UNLOCK(unit); 1392 return BCM_E_NOT_FOUND; 1393 } 1394 1395 sal_memcpy(agm_info, &AGM_INFO(unit, agm_id).attr, sizeof(*agm_info)); 1396 1397 AGM_UNLOCK(unit); 1398 return rv; 1399 } 1400 1401 /* 1402 * Function: 1403 * bcm_esw_switch_agm_enable_get 1404 * Purpose: 1405 * Return a monitor entry's enable status 1406 */ 1407 int 1408 bcm_th_switch_agm_enable_get(int unit, bcm_switch_agm_id_t agm_id, int *enable) 1409 { 1410 int rv = BCM_E_NONE; 1411 1412 /* Validate parameters */ 1413 if (!SOC_UNIT_VALID(unit)) { 1414 return BCM_E_UNIT; 1415 } 1416 1417 if (enable == NULL) { 1418 return BCM_E_PARAM; 1419 } 1420 1421 AGM_INIT(unit); 1422 AGM_CHECK(unit, agm_id); 1423 1424 AGM_LOCK(unit); 1425 if (!AGM_INFO(unit, agm_id).in_use) { 1426 AGM_UNLOCK(unit); 1427 return BCM_E_NOT_FOUND; 1428 } 1429 *enable = AGM_INFO(unit, agm_id).running; 1430 1431 AGM_UNLOCK(unit); 1432 1433 return rv; 1434 } 1435 1436 /* 1437 * Function: 1438 * bcm_esw_switch_agm_traverse 1439 * Purpose: 1440 * Traverse over the aggregation monitor table (63 total entries) 1441 * and run callback at each entry. 1442 */ 1443 int 1444 bcm_th_switch_agm_traverse(int unit, int flags, 1445 bcm_switch_agm_traverse_cb trav_fn, 1446 void *user_data) 1447 { 1448 int i, rv = BCM_E_NONE; 1449 1450 /* Validate parameters */ 1451 if (!SOC_UNIT_VALID(unit)) { 1452 return BCM_E_UNIT; 1453 } 1454 1455 AGM_INIT(unit); 1456 1457 if (trav_fn == NULL) { 1458 return BCM_E_PARAM; 1459 } 1460 1461 /* Traverse each AGM in use */ 1462 AGM_LOCK(unit); 1463 for (i = AGM_CNTL(unit).agm_id_min; i <= AGM_CNTL(unit).agm_id_max; i++) { 1464 if (!AGM_INFO(unit, i).in_use) { 1465 continue; 1466 } 1467 1468 rv = (*trav_fn)(unit, &AGM_INFO(unit, i).attr, user_data); 1469 if (BCM_FAILURE(rv)) { 1470 break; 1471 } 1472 } 1473 AGM_UNLOCK(unit); 1474 1475 return rv; 1476 } 1477 1478 int 1479 bcm_th_switch_agm_info(int unit, bcm_switch_agm_id_t agm_id, 1480 agm_monitor_t *agm_mnt) 1481 { 1482 int rv = BCM_E_NONE; 1483 1484 if (agm_mnt == NULL) { 1485 return BCM_E_PARAM; 1486 } 1487 1488 AGM_CHECK(unit, agm_id); 1489 1490 AGM_LOCK(unit); 1491 rv = _bcm_th_switch_agm_info(unit, agm_id, agm_mnt); 1492 AGM_UNLOCK(unit); 1493 1494 return rv; 1495 } 1496 1497 int 1498 bcm_th_switch_agm_fwd_grp_update(int unit, bcm_switch_agm_id_t agm_id, 1499 int group_id) 1500 { 1501 int rv = BCM_E_NONE; 1502 1503 AGM_CHECK(unit, agm_id); 1504 1505 AGM_LOCK(unit); 1506 if (AGM_INFO(unit, agm_id).in_use) { 1507 AGM_INFO(unit, agm_id).group_id = group_id; 1508 } else { 1509 rv = BCM_E_NOT_FOUND; 1510 } 1511 AGM_UNLOCK(unit); 1512 1513 return rv; 1514 } 1515 1516 int 1517 bcm_th_switch_agm_id_get_by_group(int unit, int group_id, 1518 bcm_switch_agm_id_t *agm_id) 1519 { 1520 int i; 1521 1522 if (agm_id == NULL) { 1523 return BCM_E_PARAM; 1524 } 1525 1526 AGM_LOCK(unit); 1527 for (i = AGM_CNTL(unit).agm_id_min; i <= AGM_CNTL(unit).agm_id_max; i++) { 1528 if (AGM_INFO(unit, i).in_use && 1529 AGM_INFO(unit, i).group_id == group_id) { 1530 *agm_id = i; 1531 AGM_UNLOCK(unit); 1532 return BCM_E_NONE; 1533 } 1534 } 1535 AGM_UNLOCK(unit); 1536 1537 return BCM_E_NOT_FOUND; 1538 } 1539 /* 1540 * Update following registers/field 1541 * IFP_METER_CONTROLr, PACKET_IFG_BYTESf 1542 * EGR_COUNTER_CONTROLr, PACKET_IFG_BYTESf 1543 * EGR_COUNTER_CONTROLr, PACKET_IFG_BYTES_2f 1544 * EGR_SHAPING_CONTROLr, PACKET_IFG_BYTESf 1545 * EGR_SHAPING_CONTROLr, PACKET_IFG_BYTES_2f 1546 */ 1547 int 1548 bcm_th_xgs3_meter_adjust_set(int unit, bcm_port_t port, int arg) 1549 { 1550 int len, max_val; 1551 int i; 1552 soc_reg_t reg[3] = { IFP_METER_CONTROLr, 1553 EGR_COUNTER_CONTROLr, 1554 EGR_SHAPING_CONTROLr }; 1555 1556 if (!soc_feature(unit, soc_feature_meter_adjust)) { 1557 return BCM_E_UNAVAIL; 1558 } 1559 1560 for (i = 0; i < 3 ; ++i ) { 1561 if (SOC_REG_FIELD_VALID(unit, reg[i], PACKET_IFG_BYTESf)) { 1562 len = soc_reg_field_length(unit, reg[i], PACKET_IFG_BYTESf); 1563 max_val = (1 << len) - 1; 1564 if (arg < 0 || arg > max_val) { 1565 return BCM_E_PARAM; 1566 } 1567 SOC_IF_ERROR_RETURN( 1568 soc_reg_field32_modify(unit, reg[i], port, 1569 PACKET_IFG_BYTESf, arg)); 1570 } 1571 1572 if (SOC_REG_FIELD_VALID(unit, reg[i], PACKET_IFG_BYTES_2f)) { 1573 len = soc_reg_field_length(unit, reg[i], PACKET_IFG_BYTES_2f); 1574 max_val = (1 << len) - 1; 1575 if (arg < 0 || arg > max_val) { 1576 return BCM_E_PARAM; 1577 } 1578 SOC_IF_ERROR_RETURN( 1579 soc_reg_field32_modify(unit, reg[i], port, 1580 PACKET_IFG_BYTES_2f, arg)); 1581 } 1582 } 1583 1584 return BCM_E_NONE; 1585 } 1586 1587 int 1588 bcm_th_xgs3_meter_adjust_get(int unit, bcm_port_t port, int *arg) 1589 { 1590 uint32 val; 1591 1592 BCM_IF_ERROR_RETURN( 1593 READ_EGR_COUNTER_CONTROLr(unit, port, &val)); 1594 *arg = soc_reg_field_get(unit, EGR_COUNTER_CONTROLr, val, 1595 PACKET_IFG_BYTESf); 1596 return BCM_E_NONE; 1597 } 1598 1599 1600 #endif /* defined(BCM_TOMAHAWK_SUPPORT) */ 1601