cosq.c (116280B)
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 * COS Queue Management 8 * Purpose: API to set different cosq, priorities, and scheduler registers. 9 */ 10 11 #include <shared/bsl.h> 12 13 #include <sal/core/libc.h> 14 #include <soc/defs.h> 15 #if defined(BCM_HURRICANE_SUPPORT) 16 #include <soc/drv.h> 17 #include <soc/scache.h> 18 #include <soc/profile_mem.h> 19 #include <soc/debug.h> 20 #include <soc/hurricane.h> 21 22 #include <bcm/error.h> 23 #include <bcm/cosq.h> 24 25 #include <bcm_int/esw/cosq.h> 26 #include <bcm_int/esw/mbcm.h> 27 #include <bcm_int/esw/firebolt.h> 28 #include <bcm_int/esw/hurricane.h> 29 #ifdef BCM_GREYHOUND_SUPPORT 30 #include <bcm_int/esw/greyhound.h> 31 #include <bcm_int/esw/ecn.h> 32 #endif /* BCM_GREYHOUND_SUPPORT */ 33 #ifdef BCM_HURRICANE3_SUPPORT 34 #include <bcm_int/esw/hurricane3.h> 35 #endif /* BCM_HURRICANE3_SUPPORT */ 36 37 #include <bcm_int/esw_dispatch.h> 38 39 #ifdef BCM_WARM_BOOT_SUPPORT 40 #include <bcm_int/esw/switch.h> 41 #endif /* BCM_WARM_BOOT_SUPPORT */ 42 43 44 #define BCM_HU_MTU_QUANTA_ID_COUNT 4 45 #define BCM_HU_COS_WEIGHT_MAX 0x7f 46 47 48 /* COSQ where output of hierarchical COSQs scheduler is attached */ 49 50 /* MMU cell size in bytes */ 51 52 53 #define MMU_CELL_SIZE 128 /* not overrideable */ 54 #define MMU_FLOW_PERCENT 90 55 #define MMU_FLOW_FANIN 4 56 #define MMU_FLOW_PKTMIN 8 /* not overrideable */ 57 #define MMU_RED_DROP_PERCENT 60 58 #define MMU_YELLOW_DROP_PERCENT 80 59 #define MMU_STATIC_BYTES (1536 * 1) 60 #define MMU_STATIC_PERCENT 50 /* not used if STATIC_BYTES set */ 61 #define MMU_RESET_BYTES (1536 * 2) 62 #define MMU_RESET_MIN_PERCENT 50 /* not overrideable */ 63 #define MMU_OVERCOMMIT 1 /* non-stack dynamic cell overcommit */ 64 #define MMU_OVERCOMMIT_STACK 2 /* stack dynamic cell overcommit */ 65 66 #define BCM_HU_CNG_PKT_LIMIT_GRANULARITY 4 67 #define HU_DRR_KBYTES (1) 68 #define HU_DRR_WEIGHT_MAX 0x7f 69 #define HU_WRR_WEIGHT_MAX 0x7f 70 71 /* COS Map profile entries per set */ 72 #define HU_COS_MAP_ENTRIES_PER_SET 16 73 74 #define HU_BURST_GRANULARITY 64 /* 64bytes */ 75 #define HU_BURST_GRANULARITY_DEFAULT HU_BURST_GRANULARITY 76 #define HU_BURST_GRANULARITY_128B 128 /* 128 bytes */ 77 #define HU_BW_FIELD_MAX 0x3FFFF 78 79 80 81 /* Cache of COS_MAP Profile Table */ 82 STATIC soc_profile_mem_t *_hu_cos_map_profile[BCM_MAX_NUM_UNITS] = {NULL}; 83 84 #ifdef BCM_GREYHOUND_SUPPORT 85 #define GH_CELL_FIELD_MAX 0x3fff 86 /* MMU cell size in bytes */ 87 #define _BCM_GH_BYTES_PER_CELL 128 /* bytes */ 88 #define _BCM_GH_BYTES_TO_CELLS(_byte_) \ 89 (((_byte_) + _BCM_GH_BYTES_PER_CELL - 1) / _BCM_GH_BYTES_PER_CELL) 90 91 STATIC soc_profile_mem_t *_bcm_gh_wred_profile[BCM_MAX_NUM_UNITS]; 92 93 /* WRED update interval unit : us */ 94 STATIC int _bcm_gh_wred_update_interval[BCM_MAX_NUM_UNITS]; 95 96 #endif /* BCM_GREYHOUND_SUPPORT */ 97 98 /* Number of COSQs configured for this device */ 99 STATIC int _hu_num_cosq[SOC_MAX_NUM_DEVICES]; 100 101 102 STATIC soc_field_t 103 _hu_cosfld[] = { 104 COS0THDMODEf, 105 COS1THDMODEf, 106 COS2THDMODEf, 107 COS3THDMODEf, 108 COS4THDMODEf, 109 COS5THDMODEf, 110 COS6THDMODEf, 111 COS7THDMODEf, 112 }; 113 114 /* 115 * Convert HW drop probability to percent value 116 */ 117 STATIC int 118 _bcm_hu_hw_drop_prob_to_api_val[] = { 119 1000, /* 0 */ 120 125, /* 1 */ 121 63, /* 2 */ 122 31, /* 3 */ 123 16, /* 4 */ 124 8, /* 5 */ 125 4, /* 6 */ 126 2, /* 7 */ 127 }; 128 129 STATIC int 130 _bcm_hu2_hw_drop_prob_to_api_val[] = { 131 1000, /* 0 */ 132 63, /* 1 */ 133 31, /* 2 */ 134 16, /* 3 */ 135 8, /* 4 */ 136 4, /* 5 */ 137 2, /* 6 */ 138 1, /* 7 */ 139 }; 140 141 142 static int MTU_HU_Quanta[BCM_HU_MTU_QUANTA_ID_COUNT] = { 143 2 * HU_DRR_KBYTES, /* Quanta of 2048 bytes */ 144 4 * HU_DRR_KBYTES, /* Quanta of 4096 bytes */ 145 8 * HU_DRR_KBYTES, /* Quanta of 8192 bytes */ 146 16 * HU_DRR_KBYTES /* Quanta of 16384 bytes */ 147 }; 148 149 /*Forward Declaration*/ 150 STATIC int 151 _bcm_hu_cosq_port_sched_get(int unit, soc_reg_t config_reg, 152 soc_reg_t weight_reg, bcm_port_t port, 153 bcm_cos_queue_t start_cosq, 154 int num_weights, int weights[], int *mode); 155 156 STATIC int 157 _bcm_hu_cosq_config_set(int unit, int numq); 158 159 STATIC int 160 _bcm_hu_cosq_port_sched_set(int unit, soc_reg_t config_reg, 161 soc_reg_t weight_reg, bcm_port_t port, 162 bcm_cos_queue_t start_cosq, 163 int num_weights, const int weights[], 164 int mode); 165 166 STATIC int 167 _bcm_hu_api_val_to_hw_drop_prob(int api_val) { 168 int i; 169 for (i = 7; i > 0 ; i--) { 170 if (api_val <= _bcm_hu_hw_drop_prob_to_api_val[i]) { 171 break; 172 } 173 } 174 return i; 175 } 176 177 STATIC int 178 _bcm_hu2_api_val_to_hw_drop_prob(int api_val) { 179 int i; 180 for (i = 7; i > 0 ; i--) { 181 if (api_val <= _bcm_hu2_hw_drop_prob_to_api_val[i]) { 182 break; 183 } 184 } 185 return i; 186 } 187 188 189 static int 190 _bcm_hu_cos_max_weight(const int weight[]) 191 { 192 int i, max_weight = 0; 193 194 /* find max weight */ 195 for (i = 0; i < 8; i++ ) { 196 if (max_weight < weight[i]) { 197 max_weight = weight[i]; 198 } 199 } 200 return max_weight; 201 } 202 203 204 STATIC int 205 _bcm_hu_cosq_resolve_mod_port(int unit, bcm_gport_t gport, 206 bcm_module_t *modid, bcm_port_t *port, 207 bcm_trunk_t *trunk_id, int *is_local) 208 { 209 int gport_id; 210 211 BCM_IF_ERROR_RETURN 212 (_bcm_esw_gport_resolve(unit, gport, modid, 213 port, trunk_id, &gport_id)); 214 BCM_IF_ERROR_RETURN( 215 _bcm_esw_modid_is_local(unit, *modid, is_local)); 216 217 return BCM_E_NONE; 218 } 219 220 /* 221 * Calculates the Quanta needed for COS according to its weight 222 */ 223 static int 224 _bcm_hu_cos_drr_weights_to_quanta(const int weight[]) 225 { 226 int i, max_weight = 0; 227 228 max_weight = _bcm_hu_cos_max_weight(weight); 229 230 for (i = 0; i < BCM_HU_MTU_QUANTA_ID_COUNT; i++ ) { 231 if (max_weight <= MTU_HU_Quanta[i] * BCM_HU_COS_WEIGHT_MAX) { 232 return i; /* Right Quanta was found */ 233 } 234 } 235 return -1; /* In case of too big weight return negative value */ 236 } 237 /* 238 * Convert the number of kbytes (1024 bytes) that can transmtted in one run 239 * to weight encoding 240 */ 241 static int 242 _bcm_hu_mtu_cos_drr_kbytes_to_weight(int kbytes, int MTUQuantaSel) 243 { 244 int cos_weight = 0; 245 int weight_found = FALSE, low_weight_boundary, hi_weight_boundary; 246 247 /* Search for right weight */ 248 low_weight_boundary = 1; 249 hi_weight_boundary = BCM_HU_COS_WEIGHT_MAX; 250 251 /* Boundary conditions */ 252 if (kbytes >= hi_weight_boundary * MTU_HU_Quanta[MTUQuantaSel]) { 253 cos_weight = hi_weight_boundary; 254 weight_found = TRUE; 255 } 256 if (kbytes <= low_weight_boundary * MTU_HU_Quanta[MTUQuantaSel]) { 257 cos_weight = low_weight_boundary; 258 weight_found = TRUE; 259 } 260 while (!weight_found) { 261 cos_weight = (hi_weight_boundary + low_weight_boundary) / 2; 262 if (kbytes <= cos_weight * MTU_HU_Quanta[MTUQuantaSel]) { 263 if (kbytes > ((cos_weight - 1) * MTU_HU_Quanta[MTUQuantaSel])) { 264 weight_found = TRUE; 265 } else { 266 hi_weight_boundary = cos_weight; 267 } 268 } else { 269 if (kbytes <= ((cos_weight + 1) * MTU_HU_Quanta[MTUQuantaSel])) { 270 cos_weight++; 271 weight_found = TRUE; 272 } else { 273 low_weight_boundary = cos_weight; 274 } 275 } 276 } /* Here weight should be found */ 277 return cos_weight; 278 } 279 280 /* 281 * Convert the encoded weights to number of kbytes that can transmtted 282 * in one run. 283 */ 284 static int 285 _bcm_hu_mtu_cos_drr_weight_to_kbytes(int weight, int MTUQuantaSel) 286 { 287 return (weight * MTU_HU_Quanta[MTUQuantaSel]); 288 } 289 290 #ifdef BCM_WARM_BOOT_SUPPORT 291 292 #define BCM_WB_VERSION_1_0 SOC_SCACHE_VERSION(1,0) 293 #define BCM_WB_DEFAULT_VERSION BCM_WB_VERSION_1_0 294 295 /* 296 * Function: 297 * bcm_hu_cosq_sync 298 * Purpose: 299 * Record COSQ module persistent info for Level 2 Warm Boot. 300 * Parameters: 301 * unit - Unit number. 302 * Returns: 303 * BCM_E_XXX 304 */ 305 int 306 bcm_hu_cosq_sync(int unit) 307 { 308 soc_scache_handle_t scache_handle; 309 uint8 *cosq_scache_ptr; 310 uint32 num_cosq; 311 312 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 0); 313 BCM_IF_ERROR_RETURN 314 (_bcm_esw_scache_ptr_get(unit, scache_handle, FALSE, 315 0, &cosq_scache_ptr, 316 BCM_WB_DEFAULT_VERSION, NULL)); 317 318 /* Number COSQ */ 319 num_cosq = _hu_num_cosq[unit]; 320 sal_memcpy(cosq_scache_ptr, &num_cosq, sizeof(num_cosq)); 321 322 return BCM_E_NONE; 323 } 324 325 /* 326 * Function: 327 * _bcm_hu_cosq_reinit 328 * Purpose: 329 * Recover COSQ software state. 330 * Parameters: 331 * unit - Unit number. 332 * Returns: 333 * BCM_E_XXX 334 */ 335 STATIC int 336 _bcm_hu_cosq_reinit(int unit) 337 { 338 int rv; 339 soc_scache_handle_t scache_handle; 340 uint8 *cosq_scache_ptr; 341 uint32 num_cosq; 342 #ifdef BCM_GREYHOUND_SUPPORT 343 int i, profile_index; 344 mmu_wred_config_entry_t qentry; 345 #endif /* BCM_GREYHOUND_SUPPORT */ 346 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 0); 347 rv = _bcm_esw_scache_ptr_get(unit, scache_handle, FALSE, 348 0, &cosq_scache_ptr, 349 BCM_WB_DEFAULT_VERSION, NULL); 350 351 if (rv == BCM_E_NOT_FOUND) { 352 cosq_scache_ptr = NULL; 353 } else if (BCM_FAILURE(rv)) { 354 return rv; 355 } 356 357 if (cosq_scache_ptr != NULL) { 358 /* Number COSQ */ 359 sal_memcpy(&num_cosq, cosq_scache_ptr, sizeof(num_cosq)); 360 _hu_num_cosq[unit] = num_cosq; 361 } else { 362 _hu_num_cosq[unit] = _bcm_esw_cosq_config_property_get(unit); 363 } 364 365 #ifdef BCM_GREYHOUND_SUPPORT 366 if (soc_feature(unit, soc_feature_discard_ability)) { 367 for (i = soc_mem_index_min(unit, MMU_WRED_CONFIGm); 368 i <= soc_mem_index_max(unit, MMU_WRED_CONFIGm); i++) { 369 BCM_IF_ERROR_RETURN( 370 soc_mem_read(unit, MMU_WRED_CONFIGm, 371 MEM_BLOCK_ALL, i, &qentry)); 372 373 profile_index = soc_mem_field32_get(unit, MMU_WRED_CONFIGm, 374 &qentry, PROFILE_INDEXf); 375 376 BCM_IF_ERROR_RETURN 377 (soc_profile_mem_reference(unit, _bcm_gh_wred_profile[unit], 378 profile_index, 1)); 379 } 380 } 381 #endif /* BCM_GREYHOUND_SUPPORT */ 382 383 return BCM_E_NONE; 384 } 385 #endif /* BCM_WARM_BOOT_SUPPORT */ 386 387 /* Function: 388 * bcm_hu_cosq_init 389 * Purpose: 390 * Initialize (clear) all COS schedule/mapping state. 391 * Parameters: 392 * unit - StrataSwitch unit number. 393 * Returns: 394 * BCM_E_XXX 395 */ 396 397 int 398 bcm_hu_cosq_init(int unit) 399 { 400 STATIC int _hu_max_cosq = -1; 401 int num_cos = 0; 402 #ifdef BCM_WARM_BOOT_SUPPORT 403 int rv; 404 soc_scache_handle_t scache_handle; 405 uint32 cosq_scache_size; 406 uint8 *cosq_scache_ptr; 407 #endif /* BCM_WARM_BOOT_SUPPORT */ 408 #ifdef BCM_GREYHOUND_SUPPORT 409 static soc_mem_t wred_mems[6] = { 410 MMU_WRED_DROP_PROFILE_GREENm, 411 MMU_WRED_DROP_PROFILE_YELLOWm, 412 MMU_WRED_DROP_PROFILE_REDm, 413 MMU_WRED_MARK_PROFILE_GREENm, 414 MMU_WRED_MARK_PROFILE_YELLOWm, 415 MMU_WRED_MARK_PROFILE_REDm 416 }; 417 418 int entry_words[6]; 419 uint32 interval; 420 #endif /* BCM_GREYHOUND_SUPPORT */ 421 422 if (_hu_max_cosq < 0) { 423 _hu_max_cosq = NUM_COS(unit); 424 NUM_COS(unit) = 8; 425 } 426 427 if (!SOC_WARM_BOOT(unit)) { /* Cold Boot */ 428 BCM_IF_ERROR_RETURN (bcm_hu_cosq_detach(unit, 0)); 429 #if defined(BCM_GREYHOUND_SUPPORT) 430 if (soc_feature(unit, soc_feature_discard_ability)) { 431 BCM_IF_ERROR_RETURN( 432 soc_mem_clear(unit, MMU_WRED_CONFIGm, COPYNO_ALL, TRUE)); 433 } 434 #endif /* BCM_GREYHOUND_SUPPORT */ 435 } 436 437 num_cos = _bcm_esw_cosq_config_property_get(unit); 438 439 #ifdef BCM_GREYHOUND_SUPPORT 440 if (soc_feature(unit, soc_feature_discard_ability)) { 441 /* Create profile for MMU_WRED_DROP_CURVE_PROFILE_x tables */ 442 if (_bcm_gh_wred_profile[unit] == NULL) { 443 _bcm_gh_wred_profile[unit] = 444 sal_alloc(sizeof(soc_profile_mem_t), "WRED Profile Mem"); 445 if (_bcm_gh_wred_profile[unit] == NULL) { 446 return BCM_E_MEMORY; 447 } 448 soc_profile_mem_t_init(_bcm_gh_wred_profile[unit]); 449 } else { 450 soc_profile_mem_destroy(unit, _bcm_gh_wred_profile[unit]); 451 } 452 453 entry_words[0] = 454 sizeof(mmu_wred_drop_profile_green_entry_t) / sizeof(uint32); 455 entry_words[1] = 456 sizeof(mmu_wred_drop_profile_yellow_entry_t) / sizeof(uint32); 457 entry_words[2] = 458 sizeof(mmu_wred_drop_profile_red_entry_t) / sizeof(uint32); 459 entry_words[3] = 460 sizeof(mmu_wred_mark_profile_green_entry_t) / sizeof(uint32); 461 entry_words[4] = 462 sizeof(mmu_wred_mark_profile_yellow_entry_t) / sizeof(uint32); 463 entry_words[5] = 464 sizeof(mmu_wred_mark_profile_red_entry_t) / sizeof(uint32); 465 BCM_IF_ERROR_RETURN 466 (soc_profile_mem_create(unit, wred_mems, entry_words, 6, 467 _bcm_gh_wred_profile[unit])); 468 469 /* 470 * WRED update inetrval 471 * For the SKUs that system core clock is at 300Mhz, 472 * the WRED update interval is changed to 1us from 2us(default) 473 */ 474 if (SOC_IS_GREYHOUND(unit)) { 475 if (soc_feature(unit, soc_feature_core_clock_300m)) { 476 _bcm_gh_wred_update_interval[unit] = 1; /* 1 us */ 477 BCM_IF_ERROR_RETURN( 478 soc_reg_field32_modify(unit, TIME_DOMAINr, 479 REG_PORT_ANY, WRED_UPDATE_INTERVALf, 0)); 480 } else { 481 _bcm_gh_wred_update_interval[unit] = 2; /* 2 us */ 482 } 483 } else { 484 /* HURRICANE3 */ 485 /* WRED_UPDATE_INTERVAL = 240 * (1+2/16) * core_clock_period */ 486 interval = 240 * (1+2/16) / SOC_INFO(unit).frequency; 487 BCM_IF_ERROR_RETURN( 488 soc_reg_field32_modify(unit, TIME_DOMAINr, 489 REG_PORT_ANY, WRED_UPDATE_INTERVALf, interval)); 490 _bcm_gh_wred_update_interval[unit] = interval + 1; 491 } 492 } 493 #endif /* BCM_GREYHOUND_SUPPORT */ 494 495 #ifdef BCM_WARM_BOOT_SUPPORT 496 /* Warm boot level 2 cache size */ 497 cosq_scache_size = sizeof(uint32); /* Number COSQ */ 498 499 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 0); 500 rv = _bcm_esw_scache_ptr_get(unit, scache_handle, 501 (0 == SOC_WARM_BOOT(unit)), 502 cosq_scache_size, &cosq_scache_ptr, 503 BCM_WB_DEFAULT_VERSION, NULL); 504 if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) { 505 return rv; 506 } 507 508 if (SOC_WARM_BOOT(unit)) { 509 BCM_IF_ERROR_RETURN(_bcm_hu_cosq_reinit(unit)); 510 num_cos = _hu_num_cosq[unit]; 511 } 512 #endif /* BCM_WARM_BOOT_SUPPORT */ 513 514 return bcm_hu_cosq_config_set(unit, num_cos); 515 } 516 517 518 519 520 521 int 522 bcm_hu_cosq_port_sched_set(int unit, bcm_pbmp_t pbm, 523 int mode, const int weights[], int delay) 524 { 525 uint32 wrr; 526 int port; 527 uint32 cosarbsel; 528 int mbits = 0; 529 int i, max_weight; 530 int enc_weights[8]; 531 int MTUQuantaSel = 0; 532 int num_cosq; 533 534 COMPILER_REFERENCE(delay); 535 536 /* Activated cosq number */ 537 num_cosq = _hu_num_cosq[unit]; 538 539 mbcm_driver[unit]->mbcm_cosq_sched_weight_max_get(unit, mode, &max_weight); 540 if((mode != BCM_COSQ_STRICT) && (mode != BCM_COSQ_ROUND_ROBIN) && 541 (max_weight != BCM_COSQ_WEIGHT_UNLIMITED)) { 542 for(i = 0; i < num_cosq; i++) { 543 if((weights[i] < 0) || (weights[i] > max_weight)) { 544 return BCM_E_PARAM; 545 } 546 } 547 } 548 549 switch (mode) { 550 case BCM_COSQ_STRICT: 551 mbits = 0; 552 break; 553 case BCM_COSQ_ROUND_ROBIN: 554 mbits = 1; 555 break; 556 case BCM_COSQ_WEIGHTED_ROUND_ROBIN: 557 mbits = 2; 558 /* 559 * All weight values must fit within 7 bits. 560 * If weight is 0, this queue is run in strict mode, 561 * others run in WRR mode. 562 */ 563 564 for(i = 0; i < num_cosq; i++) { 565 enc_weights[i] = weights[i]; 566 } 567 break; 568 case BCM_COSQ_DEFICIT_ROUND_ROBIN: 569 mbits = 3; 570 if (soc_feature(unit, soc_feature_linear_drr_weight)) { 571 MTUQuantaSel = _bcm_hu_cos_drr_weights_to_quanta(weights); 572 if (MTUQuantaSel < 0) { 573 return BCM_E_PARAM; 574 } 575 for (i = 0; i < num_cosq; i++) { 576 if (weights[i]) { 577 enc_weights[i] = 578 _bcm_hu_mtu_cos_drr_kbytes_to_weight(weights[i], 579 MTUQuantaSel); 580 } else { 581 enc_weights[i] = weights[i]; 582 } 583 } 584 }/*soc_feature_linear_drr_weight*/ 585 break; 586 case BCM_COSQ_BOUNDED_DELAY: /* not supported in xgs */ 587 default: 588 return BCM_E_PARAM; 589 } 590 591 PBMP_ITER(pbm, port) { 592 cosarbsel = 0; 593 soc_reg_field_set(unit, XQCOSARBSELr, &cosarbsel, COSARBf, mbits); 594 if ((mode == BCM_COSQ_DEFICIT_ROUND_ROBIN) && 595 (soc_feature(unit, soc_feature_linear_drr_weight))) { 596 soc_reg_field_set(unit, XQCOSARBSELr, &cosarbsel, 597 MTU_QUANTA_SELECTf, MTUQuantaSel); 598 } 599 SOC_IF_ERROR_RETURN(WRITE_XQCOSARBSELr(unit, port, cosarbsel)); 600 } 601 602 if ((mode == BCM_COSQ_WEIGHTED_ROUND_ROBIN) || 603 (mode == BCM_COSQ_DEFICIT_ROUND_ROBIN)) { 604 /* 605 * Weighted Fair Queueing scheduling among vaild COSs 606 */ 607 PBMP_ITER(pbm, port) { 608 if (soc_feature(unit, soc_feature_linear_drr_weight)) { 609 for (i = 0; i < num_cosq; i++) { 610 SOC_IF_ERROR_RETURN(READ_WRRWEIGHT_COSr(unit, port, 611 i, &wrr)); 612 soc_reg_field_set(unit, WRRWEIGHT_COSr, &wrr, 613 WEIGHTf, enc_weights[i]); 614 SOC_IF_ERROR_RETURN(WRITE_WRRWEIGHT_COSr(unit, port, 615 i, wrr)); 616 } 617 } 618 } 619 } 620 return BCM_E_NONE; 621 } 622 623 /* 624 * Function: 625 * bcm_cosq_port_sched_get 626 * Purpose: 627 * Retrieve class-of-service policy and corresponding weights and delay 628 * Parameters: 629 * unit - StrataSwitch unit number. 630 * pbm - port bitmap 631 * mode - (output) Scheduling mode, one of BCM_COSQ_xxx 632 * weights - (output) Weights for each COS queue 633 * Only for BCM_COSQ_WEIGHTED_ROUND_ROBIN and 634 * BCM_COSQ_DEFICIT_ROUND_ROBIN mode. 635 * For DRR Weight is specified in Kbytes 636 * delay - This parameter is not used 637 * Returns: 638 * BCM_E_XXX 639 * Notes: 640 * Actually just returns data for the first port in the bitmap 641 */ 642 643 int 644 bcm_hu_cosq_port_sched_get(int unit, bcm_pbmp_t pbm, 645 int *mode, int weights[], int *delay) 646 { 647 uint32 cosarbsel, wrr; 648 int mbits, port,i; 649 int MTUQuantaSel = -1; 650 int num_cosq; 651 652 /* Activated cosq number */ 653 num_cosq = _hu_num_cosq[unit]; 654 655 mbits = -1; 656 PBMP_ITER(pbm, port) { 657 SOC_IF_ERROR_RETURN(READ_XQCOSARBSELr(unit, port, &cosarbsel)); 658 mbits = soc_reg_field_get(unit, XQCOSARBSELr, cosarbsel, COSARBf); 659 if(soc_feature(unit, soc_feature_linear_drr_weight)) { 660 MTUQuantaSel = 661 soc_reg_field_get(unit, XQCOSARBSELr, cosarbsel, 662 MTU_QUANTA_SELECTf); 663 } 664 break; 665 } 666 switch (mbits) { 667 case 0: 668 *mode = BCM_COSQ_STRICT; 669 break; 670 case 1: 671 *mode = BCM_COSQ_ROUND_ROBIN; 672 break; 673 case 2: 674 *mode = BCM_COSQ_WEIGHTED_ROUND_ROBIN; 675 break; 676 case 3: 677 *mode = BCM_COSQ_DEFICIT_ROUND_ROBIN; 678 break; 679 default: 680 return BCM_E_INTERNAL; 681 } 682 if ((mbits == 2) || (mbits == 3)) { 683 wrr = 0; 684 if (soc_feature(unit, soc_feature_linear_drr_weight)) { 685 PBMP_ITER(pbm, port) { 686 for (i = 0; i < num_cosq; i++) { 687 SOC_IF_ERROR_RETURN(READ_WRRWEIGHT_COSr(unit, port, 688 i, &wrr)); 689 weights[i] = soc_reg_field_get(unit, WRRWEIGHT_COSr, 690 wrr, WEIGHTf); 691 } 692 } 693 } 694 if (mbits == 3) { 695 int i; 696 for(i = 0; i < num_cosq; i++) { 697 if (soc_feature(unit, soc_feature_linear_drr_weight)) { 698 weights[i] = 699 _bcm_hu_mtu_cos_drr_weight_to_kbytes(weights[i], 700 MTUQuantaSel); 701 } 702 } 703 } 704 } 705 if (delay) { 706 *delay = 0; 707 } 708 return BCM_E_NONE; 709 } 710 711 712 int 713 bcm_hu_cosq_port_bandwidth_set(int unit, bcm_port_t port, 714 bcm_cos_queue_t cosq, 715 uint32 kbits_sec_min, 716 uint32 kbits_sec_max, 717 uint32 kbits_sec_burst, 718 uint32 flags) 719 { 720 uint32 regval, rval = 0; 721 uint32 bucket_val = 0; 722 uint32 burst_size = 0; 723 uint32 refresh_rate, bucketsize, granularity = 3, meter_flags = 0; 724 int refresh_bitsize, bucket_bitsize; 725 uint32 fval = 0; 726 uint32 eav_gran = HU_BURST_GRANULARITY_DEFAULT; 727 728 /* 729 * To set the new Bandwidth settings, the procedure adopted is 730 * a. reset MAXBUCKETCONFIG, MINBUCKETCONFIG, MAXBUCKET,MINBUCKET 731 * b. update MAXBUCKETCONFIG and MINBUCKETCONFIG with new values passed 732 * c. if MISCCONFIG.METERING_CLK_EN not set before, enable it. 733 */ 734 735 /*for hurricane there is only one formula for ITU weight hence no need of selection*/ 736 737 /* Disable egress metering for this port */ 738 BCM_IF_ERROR_RETURN(READ_MAXBUCKETCONFIGr(unit, port, cosq, ®val)); 739 soc_reg_field_set(unit, MAXBUCKETCONFIGr, ®val, MAX_REFRESHf, 0); 740 soc_reg_field_set(unit, MAXBUCKETCONFIGr, ®val, MAX_THD_SELf, 0); 741 BCM_IF_ERROR_RETURN(WRITE_MAXBUCKETCONFIGr(unit, port, cosq, regval)); 742 743 BCM_IF_ERROR_RETURN(READ_MINBUCKETCONFIGr(unit, port, cosq, ®val)); 744 soc_reg_field_set(unit, MINBUCKETCONFIGr, ®val, MIN_REFRESHf, 0); 745 soc_reg_field_set(unit, MINBUCKETCONFIGr, ®val, MIN_THD_SELf, 0); 746 BCM_IF_ERROR_RETURN(WRITE_MINBUCKETCONFIGr(unit, port, cosq, regval)); 747 748 /*reset the MAXBUCKET register*/ 749 soc_reg_field_set(unit, MAXBUCKETr, &bucket_val, MAX_BUCKETf, 0); 750 soc_reg_field_set(unit, MAXBUCKETr, &bucket_val, IN_PROFILE_FLAGf, 0); 751 BCM_IF_ERROR_RETURN(WRITE_MAXBUCKETr(unit, port, cosq, bucket_val)); 752 753 /*reset the MINBUCKET register value*/ 754 soc_reg_field_set(unit, MINBUCKETr, &bucket_val, MIN_BUCKETf, 0); 755 soc_reg_field_set(unit, MINBUCKETr, &bucket_val, IN_PROFILE_FLAGf, 0); 756 BCM_IF_ERROR_RETURN(WRITE_MINBUCKETr(unit, port, cosq, bucket_val)); 757 758 refresh_bitsize = 759 soc_reg_field_length(unit, MINBUCKETCONFIGr, MIN_REFRESHf); 760 bucket_bitsize = 761 soc_reg_field_length(unit, MINBUCKETCONFIGr, MIN_THD_SELf); 762 763 if (SOC_IS_HURRICANE3(unit) || SOC_IS_GREYHOUND2(unit)) { 764 meter_flags |= _BCM_XGS_METER_FLAG_GRANULARITY_SELECTIVE; 765 meter_flags |= _BCM_XGS_METER_FLAG_GRANULARITY_SELECT3; 766 meter_flags |= _BCM_XGS_METER_FLAG_GRANULARITY_SELECT5; 767 meter_flags |= _BCM_XGS_METER_FLAG_BUCKET_IN_8KB; 768 } 769 770 BCM_IF_ERROR_RETURN 771 (_bcm_xgs_kbits_to_bucket_encoding(kbits_sec_min, kbits_sec_min, 772 meter_flags, refresh_bitsize, bucket_bitsize, 773 &refresh_rate, &bucketsize, &granularity)); 774 775 if (SOC_IS_HURRICANE3(unit) || SOC_IS_GREYHOUND2(unit)) { 776 SOC_IF_ERROR_RETURN(READ_SHAPING_Q_GRANr(unit, port, ®val)); 777 if (soc_reg_field_valid(unit, SHAPING_Q_GRANr, MIN_Q_GRANf)) { 778 fval = soc_reg_field_get(unit, SHAPING_Q_GRANr, 779 regval, MIN_Q_GRANf); 780 if (granularity == 5) { 781 fval |= (1 << cosq); 782 } else { 783 fval &= ~(1 << cosq); 784 } 785 soc_reg_field_set(unit, SHAPING_Q_GRANr, ®val, 786 MIN_Q_GRANf, fval); 787 } 788 SOC_IF_ERROR_RETURN(WRITE_SHAPING_Q_GRANr(unit, port, regval)); 789 } 790 791 regval = 0; 792 soc_reg_field_set(unit, MINBUCKETCONFIGr, ®val, 793 MIN_REFRESHf, refresh_rate); 794 soc_reg_field_set(unit, MINBUCKETCONFIGr, ®val, 795 MIN_THD_SELf, bucketsize); 796 BCM_IF_ERROR_RETURN 797 (WRITE_MINBUCKETCONFIGr(unit, port, cosq, regval)); 798 799 refresh_bitsize = 800 soc_reg_field_length(unit, MAXBUCKETCONFIGr, MAX_REFRESHf); 801 bucket_bitsize = 802 soc_reg_field_length(unit, MAXBUCKETCONFIGr, MAX_THD_SELf); 803 804 BCM_IF_ERROR_RETURN 805 (_bcm_xgs_kbits_to_bucket_encoding(kbits_sec_max, kbits_sec_burst, 806 meter_flags, refresh_bitsize, bucket_bitsize, 807 &refresh_rate, &bucketsize, &granularity)); 808 809 if (SOC_IS_HURRICANE3(unit) || SOC_IS_GREYHOUND2(unit)) { 810 SOC_IF_ERROR_RETURN(READ_SHAPING_Q_GRANr(unit, port, ®val)); 811 if (soc_reg_field_valid(unit, SHAPING_Q_GRANr, MAX_Q_GRANf)) { 812 fval = soc_reg_field_get(unit, SHAPING_Q_GRANr, 813 regval, MAX_Q_GRANf); 814 if (granularity == 5) { 815 fval |= (1 << cosq); 816 } else { 817 fval &= ~(1 << cosq); 818 } 819 soc_reg_field_set(unit, SHAPING_Q_GRANr, ®val, 820 MAX_Q_GRANf, fval); 821 } 822 SOC_IF_ERROR_RETURN(WRITE_SHAPING_Q_GRANr(unit, port, regval)); 823 } 824 825 regval = 0; 826 soc_reg_field_set(unit, MAXBUCKETCONFIGr, ®val, 827 MAX_REFRESHf, refresh_rate); 828 if (flags & BCM_COSQ_BW_EAV_MODE) { 829 if ((SOC_IS_HURRICANE3(unit) || SOC_IS_GREYHOUND2(unit)) && 830 (granularity == 5)) { 831 eav_gran = HU_BURST_GRANULARITY_128B; 832 } else { 833 eav_gran = HU_BURST_GRANULARITY_DEFAULT; 834 } 835 burst_size = (((kbits_sec_burst * 1000) / 8) + 836 (eav_gran - 1)) / eav_gran; 837 if (burst_size > HU_BW_FIELD_MAX) { 838 burst_size = HU_BW_FIELD_MAX; 839 } 840 841 soc_reg_field_set(unit, MAXBUCKETCONFIGr, ®val, EAV_MODEf, 1); 842 843 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, EAVBUCKETCONFIG_EXTr, port, 844 cosq, &rval)); 845 soc_reg_field_set(unit, EAVBUCKETCONFIG_EXTr, &rval, EAV_THD_SEL_6LSBf, 846 burst_size & 0x3f); 847 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, EAVBUCKETCONFIG_EXTr, port, 848 cosq, rval)); 849 soc_reg_field_set(unit, MAXBUCKETCONFIGr, ®val, MAX_THD_SELf, 850 (burst_size >> 6 & 0xFFF)); 851 } else { 852 soc_reg_field_set(unit, MAXBUCKETCONFIGr, ®val, MAX_THD_SELf, 853 bucketsize); 854 } 855 BCM_IF_ERROR_RETURN(WRITE_MAXBUCKETCONFIGr(unit, port, cosq, regval)); 856 857 /* MISCCONFIG.METERING_CLK_EN is set by chip init */ 858 859 return BCM_E_NONE; 860 } 861 862 /* 863 * Function: 864 * bcm_cosq_gport_bandwidth_get 865 * Purpose: 866 * 867 * Parameters: 868 * unit - (IN) Unit number. 869 * gport - (IN) GPORT ID. 870 * cosq - (IN) COS queue to configure, -1 for all COS queues. 871 * kbits_sec_min - (OUT) minimum bandwidth, kbits/sec. 872 * kbits_sec_max - (OUT) maximum bandwidth, kbits/sec. 873 * flags - (OUT) BCM_COSQ_BW_* 874 * Returns: 875 * BCM_E_XXX 876 */ 877 int 878 bcm_hu_cosq_gport_bandwidth_get(int unit, bcm_gport_t gport, 879 bcm_cos_queue_t cosq, uint32 *kbits_sec_min, 880 uint32 *kbits_sec_max, uint32 *flags) 881 { 882 bcm_module_t modid; 883 bcm_port_t local_port; 884 bcm_trunk_t trunk_id; 885 int is_local; 886 uint32 kbits_max_burst; /* Placeholder */ 887 888 *kbits_sec_min = *kbits_sec_max = *flags = 0; 889 890 BCM_IF_ERROR_RETURN 891 (_bcm_hu_cosq_resolve_mod_port(unit, gport, &modid, 892 &local_port, &trunk_id, &is_local)); 893 894 if (is_local) { 895 896 if (cosq >= _hu_num_cosq[unit]) { 897 return BCM_E_PARAM; 898 } else if (cosq < 0) { 899 cosq = 0; 900 } 901 902 BCM_IF_ERROR_RETURN 903 (bcm_hu_cosq_port_bandwidth_get(unit, local_port, cosq, 904 kbits_sec_min, kbits_sec_max, 905 &kbits_max_burst, flags)); 906 } else { 907 return BCM_E_PORT; 908 } 909 return BCM_E_NONE; 910 } 911 912 /* 913 * Function: 914 * bcm_hu_cosq_gport_bandwidth_set 915 * Purpose: 916 * 917 * Parameters: 918 * unit - (IN) Unit number. 919 * gport - (IN) GPORT ID. 920 * cosq - (IN) COS queue to configure, -1 for all COS queues. 921 * kbits_sec_min - (IN) minimum bandwidth, kbits/sec. 922 * kbits_sec_max - (IN) maximum bandwidth, kbits/sec. 923 * flags - (IN) BCM_COSQ_BW_* 924 * Returns: 925 * BCM_E_XXX 926 */ 927 int 928 bcm_hu_cosq_gport_bandwidth_set(int unit, bcm_gport_t gport, 929 bcm_cos_queue_t cosq, uint32 kbits_sec_min, 930 uint32 kbits_sec_max, uint32 flags) 931 { 932 bcm_module_t modid; 933 bcm_port_t local_port; 934 bcm_trunk_t trunk_id; 935 int i, is_local; 936 bcm_cos_queue_t cosq_start = 0, cosq_end = 0; 937 938 BCM_IF_ERROR_RETURN 939 (_bcm_hu_cosq_resolve_mod_port(unit, gport, &modid, 940 &local_port, &trunk_id, &is_local)); 941 942 if (is_local) { 943 944 if (cosq >= _hu_num_cosq[unit]) { 945 return BCM_E_PARAM; 946 } else if (cosq < 0) { 947 cosq_start = 0; 948 cosq_end = _hu_num_cosq[unit] - 1; 949 } else { 950 cosq_start = cosq_end = cosq; 951 } 952 for (i = cosq_start; i <= cosq_end; i++) { 953 BCM_IF_ERROR_RETURN 954 (bcm_hu_cosq_port_bandwidth_set(unit, local_port, i, 955 kbits_sec_min, 956 kbits_sec_max, 957 kbits_sec_max, 958 flags)); 959 } 960 } else { 961 return BCM_E_PORT; 962 } 963 return BCM_E_NONE; 964 } 965 966 /* 967 * Function: 968 * bcm_cosq_gport_sched_get 969 * Purpose: 970 * 971 * Parameters: 972 * unit - (IN) Unit number. 973 * gport - (IN) GPORT ID. 974 * cosq - (IN) COS queue 975 * mode - (OUT) Scheduling mode, one of BCM_COSQ_xxx 976 * weight - (OUT) Weight for the specified COS queue(s) 977 * Unused if mode is BCM_COSQ_STRICT. 978 * Returns: 979 * BCM_E_XXX 980 */ 981 int 982 bcm_hu_cosq_gport_sched_get(int unit, bcm_gport_t gport, 983 bcm_cos_queue_t cosq, int *mode, int *weight) 984 { 985 bcm_module_t modid; 986 bcm_port_t local_port; 987 bcm_trunk_t trunk_id; 988 int is_local; 989 soc_reg_t config_reg = XQCOSARBSELr; 990 soc_reg_t weight_reg = WRRWEIGHT_COSr; 991 992 *mode = *weight = 0; 993 994 BCM_IF_ERROR_RETURN 995 (_bcm_hu_cosq_resolve_mod_port(unit, gport, &modid, 996 &local_port, &trunk_id, &is_local)); 997 if (is_local) { 998 999 if (cosq >= _hu_num_cosq[unit]) { 1000 return BCM_E_PARAM; 1001 } else if (cosq < 0) { 1002 cosq = 0; 1003 } 1004 BCM_IF_ERROR_RETURN 1005 (_bcm_hu_cosq_port_sched_get(unit, config_reg, weight_reg, 1006 local_port, cosq, 1, 1007 weight, mode)); 1008 } else { 1009 return BCM_E_PORT; 1010 } 1011 return BCM_E_NONE; 1012 } 1013 1014 /* 1015 * Function: 1016 * bcm_hu_cosq_gport_sched_set 1017 * Purpose: 1018 * 1019 * Parameters: 1020 * unit - (IN) Unit number. 1021 * gport - (IN) GPORT ID. 1022 * cosq - (IN) COS queue to configure, -1 for all COS queues. 1023 * mode - (IN) Scheduling mode, one of BCM_COSQ_xxx 1024 * weight - (IN) Weight for the specified COS queue(s) 1025 * Unused if mode is BCM_COSQ_STRICT. 1026 * Returns: 1027 * BCM_E_XXX 1028 */ 1029 int 1030 bcm_hu_cosq_gport_sched_set(int unit, bcm_gport_t gport, 1031 bcm_cos_queue_t cosq, int mode, int weight) 1032 { 1033 bcm_module_t modid; 1034 bcm_port_t local_port; 1035 bcm_trunk_t trunk_id; 1036 int i, is_local; 1037 bcm_cos_queue_t cosq_start = 0; 1038 int num_weights = 1, weights[8]; 1039 soc_reg_t config_reg = XQCOSARBSELr; 1040 soc_reg_t weight_reg = WRRWEIGHT_COSr; 1041 1042 sal_memset(weights, 0, sizeof(weights)); 1043 BCM_IF_ERROR_RETURN 1044 (_bcm_hu_cosq_resolve_mod_port(unit, gport, &modid, 1045 &local_port, &trunk_id, &is_local)); 1046 1047 if (is_local) { 1048 /*if (!_hu_num_port_cosq[unit]) { 1049 return BCM_E_INIT; 1050 }*/ 1051 1052 if (cosq >= _hu_num_cosq[unit]) { 1053 return BCM_E_PARAM; 1054 } else if (cosq < 0) { 1055 cosq_start = 0; 1056 num_weights = 8; 1057 for (i = 0; i < num_weights; i++) { 1058 if (i < _hu_num_cosq[unit]) { 1059 weights[i] = weight; 1060 } else { 1061 weights[i] = 0; 1062 } 1063 } 1064 } else { 1065 cosq_start = cosq; 1066 num_weights = 1; 1067 weights[0] = weight; 1068 } 1069 1070 1071 BCM_IF_ERROR_RETURN 1072 (_bcm_hu_cosq_port_sched_set(unit, config_reg, weight_reg, 1073 local_port, cosq_start, num_weights, 1074 weights, mode)); 1075 } else { 1076 return BCM_E_PORT; 1077 } 1078 return BCM_E_NONE; 1079 } 1080 1081 1082 int 1083 bcm_hu_cosq_port_bandwidth_get(int unit, bcm_port_t port, 1084 bcm_cos_queue_t cosq, 1085 uint32 *kbits_sec_min, 1086 uint32 *kbits_sec_max, 1087 uint32 *kbits_sec_burst, 1088 uint32 *flags) 1089 { 1090 uint32 regval; 1091 uint32 refresh_rate = 0, bucketsize = 0, 1092 granularity = 3, meter_flags = 0; 1093 uint32 kbits_min_burst; /* Placeholder, since burst is unused for min */ 1094 uint32 rval = 0; 1095 uint32 bucket_lo = 0; 1096 uint32 eav_mode = 0; 1097 uint32 fval = 0; 1098 uint32 eav_gran = HU_BURST_GRANULARITY_DEFAULT; 1099 1100 if (!kbits_sec_min || !kbits_sec_max || !kbits_sec_burst || !flags) { 1101 return (BCM_E_PARAM); 1102 } 1103 1104 *flags = 0; 1105 1106 if (SOC_IS_HURRICANE3(unit) || SOC_IS_GREYHOUND2(unit)) { 1107 meter_flags |= _BCM_XGS_METER_FLAG_GRANULARITY; 1108 1109 granularity = 3; /* reset to default */ 1110 SOC_IF_ERROR_RETURN(READ_SHAPING_Q_GRANr(unit, port, ®val)); 1111 if (soc_reg_field_valid(unit, SHAPING_Q_GRANr, MIN_Q_GRANf)) { 1112 fval = soc_reg_field_get(unit, SHAPING_Q_GRANr, 1113 regval, MAX_Q_GRANf); 1114 if (fval & (1 << cosq)) { 1115 granularity = 5; 1116 } 1117 } 1118 } 1119 1120 BCM_IF_ERROR_RETURN(READ_MAXBUCKETCONFIGr(unit, port, cosq, ®val)); 1121 refresh_rate = soc_reg_field_get(unit, MAXBUCKETCONFIGr, 1122 regval, MAX_REFRESHf); 1123 bucketsize = soc_reg_field_get(unit, MAXBUCKETCONFIGr, 1124 regval, MAX_THD_SELf); 1125 eav_mode = soc_reg_field_get(unit, MAXBUCKETCONFIGr, 1126 regval, EAV_MODEf); 1127 BCM_IF_ERROR_RETURN 1128 (_bcm_xgs_bucket_encoding_to_kbits(refresh_rate, bucketsize, 1129 granularity, meter_flags, 1130 kbits_sec_max, kbits_sec_burst)); 1131 if (eav_mode == 1) { 1132 *flags |= BCM_COSQ_BW_EAV_MODE; 1133 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, EAVBUCKETCONFIG_EXTr, 1134 port, cosq, &rval)); 1135 bucket_lo = soc_reg_field_get(unit, EAVBUCKETCONFIG_EXTr, 1136 rval, EAV_THD_SEL_6LSBf); 1137 if ((SOC_IS_HURRICANE3(unit) || SOC_IS_GREYHOUND2(unit)) && 1138 (granularity == 5)) { 1139 eav_gran = HU_BURST_GRANULARITY_128B; 1140 } else { 1141 eav_gran = HU_BURST_GRANULARITY_DEFAULT; 1142 } 1143 *kbits_sec_burst = (((bucketsize << 6) | bucket_lo) * 1144 eav_gran * 8) / 1000; 1145 } 1146 1147 BCM_IF_ERROR_RETURN(READ_MINBUCKETCONFIGr(unit, port, cosq, ®val)); 1148 1149 refresh_rate = soc_reg_field_get(unit, MINBUCKETCONFIGr, 1150 regval, MIN_REFRESHf); 1151 1152 if (SOC_IS_HURRICANE3(unit) || SOC_IS_GREYHOUND2(unit)) { 1153 meter_flags = 0; /* reset to default */ 1154 granularity = 3; /* reset to default */ 1155 1156 meter_flags |= _BCM_XGS_METER_FLAG_GRANULARITY; 1157 SOC_IF_ERROR_RETURN(READ_SHAPING_Q_GRANr(unit, port, ®val)); 1158 if (soc_reg_field_valid(unit, SHAPING_Q_GRANr, MAX_Q_GRANf)) { 1159 fval = soc_reg_field_get(unit, SHAPING_Q_GRANr, 1160 regval, MIN_Q_GRANf); 1161 if (fval & (1 << cosq)) { 1162 granularity = 5; 1163 } 1164 } 1165 } 1166 1167 BCM_IF_ERROR_RETURN 1168 (_bcm_xgs_bucket_encoding_to_kbits(refresh_rate, 0, 1169 granularity, meter_flags, 1170 kbits_sec_min, &kbits_min_burst)); 1171 1172 1173 return BCM_E_NONE; 1174 } 1175 1176 1177 STATIC int 1178 _bcm_hu_cosq_port_sched_get(int unit, soc_reg_t config_reg, 1179 soc_reg_t weight_reg, bcm_port_t port, 1180 bcm_cos_queue_t start_cosq, 1181 int num_weights, int weights[], int *mode) 1182 { 1183 uint32 escfg, wrr; 1184 int mbits, i, cosq; 1185 int MTUQuantaSel = -1; 1186 1187 SOC_IF_ERROR_RETURN(READ_XQCOSARBSELr(unit, port, &escfg)); 1188 mbits = soc_reg_field_get(unit, config_reg, escfg, COSARBf); 1189 MTUQuantaSel = soc_reg_field_get(unit, config_reg, escfg, 1190 MTU_QUANTA_SELECTf); 1191 1192 switch (mbits) { 1193 case 0: 1194 *mode = BCM_COSQ_STRICT; 1195 break; 1196 case 1: 1197 *mode = BCM_COSQ_ROUND_ROBIN; 1198 break; 1199 case 2: 1200 *mode = BCM_COSQ_WEIGHTED_ROUND_ROBIN; 1201 break; 1202 case 3: 1203 *mode = BCM_COSQ_DEFICIT_ROUND_ROBIN; 1204 break; 1205 default: 1206 return BCM_E_INTERNAL; 1207 } 1208 1209 if ((mbits == 2) || (mbits == 3)) { 1210 wrr = 0; 1211 for(cosq = start_cosq, i = 0; i < num_weights; cosq++, i++) { 1212 SOC_IF_ERROR_RETURN(READ_WRRWEIGHT_COSr(unit, port, 1213 cosq, &wrr)); 1214 weights[i] = soc_reg_field_get(unit, weight_reg, wrr, 1215 WEIGHTf); 1216 } 1217 1218 if (mbits == 3) { 1219 int i; 1220 for(i = 0; i < num_weights; i++) { 1221 weights[i] = _bcm_hu_mtu_cos_drr_weight_to_kbytes(weights[i],MTUQuantaSel); 1222 } 1223 } 1224 } 1225 return BCM_E_NONE; 1226 } 1227 1228 /* 1229 * Convert the number of kbytes (1024 bytes) that can transmtted in one run 1230 * to weight encoding for 1231 */ 1232 static int 1233 _bcm_hu_cos_drr_kbytes_to_weight(int kbytes, int MTUQuantaSel) 1234 { 1235 int cos_weight = 0; 1236 int weight_found = FALSE, low_weight_boundary, hi_weight_boundary; 1237 1238 /* Search for right weight */ 1239 low_weight_boundary = 1; 1240 hi_weight_boundary = BCM_HU_COS_WEIGHT_MAX; 1241 1242 /* Boundary conditions */ 1243 if (kbytes >= hi_weight_boundary * MTU_HU_Quanta[MTUQuantaSel]) { 1244 cos_weight = hi_weight_boundary; 1245 weight_found = TRUE; 1246 } 1247 if (kbytes <= low_weight_boundary * MTU_HU_Quanta[MTUQuantaSel]) { 1248 cos_weight = low_weight_boundary; 1249 weight_found = TRUE; 1250 } 1251 1252 while (!weight_found) { 1253 cos_weight = (hi_weight_boundary + low_weight_boundary) / 2; 1254 if (kbytes <= cos_weight * MTU_HU_Quanta[MTUQuantaSel]) { 1255 if (kbytes > ((cos_weight - 1) * MTU_HU_Quanta[MTUQuantaSel])) { 1256 weight_found = TRUE; 1257 } else { 1258 hi_weight_boundary = cos_weight; 1259 } 1260 } else { 1261 if (kbytes <= ((cos_weight + 1) * MTU_HU_Quanta[MTUQuantaSel])) { 1262 cos_weight++; 1263 weight_found = TRUE; 1264 } else { 1265 low_weight_boundary = cos_weight; 1266 } 1267 } 1268 } /* Here weight should be found */ 1269 1270 return cos_weight; 1271 } 1272 1273 1274 STATIC int 1275 _bcm_hu_cosq_port_sched_set(int unit, soc_reg_t config_reg, 1276 soc_reg_t weight_reg, bcm_port_t port, 1277 bcm_cos_queue_t start_cosq, 1278 int num_weights, const int weights[], 1279 int mode) 1280 { 1281 int t, i, cosq; 1282 uint32 wrr; 1283 int mbits = 0; 1284 int enc_weights[8]; 1285 int MTUQuantaSel = 0; 1286 1287 switch (mode) { 1288 case BCM_COSQ_STRICT: 1289 mbits = 0; 1290 break; 1291 case BCM_COSQ_ROUND_ROBIN: 1292 mbits = 1; 1293 break; 1294 case BCM_COSQ_WEIGHTED_ROUND_ROBIN: 1295 mbits = 2; 1296 /* 1297 * All weight values must fit within 7 bits. 1298 * If weight is 0, this queue is run in strict mode, 1299 * others run in WRR mode. 1300 */ 1301 t = 0; 1302 for(i = 0; i < num_weights; i++) { 1303 t |= weights[i]; 1304 } 1305 if ((t & ~0x7f) != 0) { 1306 return BCM_E_PARAM; 1307 } 1308 for(i = 0; i < num_weights; i++) { 1309 enc_weights[i] = weights[i]; 1310 } 1311 break; 1312 case BCM_COSQ_DEFICIT_ROUND_ROBIN: 1313 mbits = 3; 1314 MTUQuantaSel = _bcm_hu_cos_drr_weights_to_quanta(weights); 1315 if (MTUQuantaSel < 0) { 1316 return BCM_E_PARAM; 1317 } 1318 1319 for(i = 0; i < num_weights; i++) { 1320 if (weights[i]) { 1321 enc_weights[i] = 1322 _bcm_hu_cos_drr_kbytes_to_weight(weights[i], 1323 MTUQuantaSel); 1324 } else { 1325 enc_weights[i] = weights[i]; 1326 } 1327 1328 } 1329 break; 1330 case BCM_COSQ_BOUNDED_DELAY: /* not supported in xgs */ 1331 default: 1332 return BCM_E_PARAM; 1333 } 1334 1335 /* Program the scheduling mode */ 1336 SOC_IF_ERROR_RETURN(soc_reg_field32_modify(unit, config_reg, port, 1337 COSARBf, mbits)); 1338 1339 if ((mode == BCM_COSQ_WEIGHTED_ROUND_ROBIN) || 1340 (mode == BCM_COSQ_DEFICIT_ROUND_ROBIN)) { 1341 /* 1342 * Weighted Fair Queueing scheduling among vaild COSs 1343 */ 1344 for(cosq = start_cosq, i = 0; i < num_weights; cosq++, i++) { 1345 SOC_IF_ERROR_RETURN(READ_WRRWEIGHT_COSr(unit, port, 1346 cosq, &wrr)); 1347 /* coverity[uninit_use_in_call : FALSE] */ 1348 soc_reg_field_set(unit, WRRWEIGHT_COSr, &wrr, 1349 WEIGHTf, enc_weights[i]); 1350 SOC_IF_ERROR_RETURN(WRITE_WRRWEIGHT_COSr(unit, port, 1351 cosq, wrr)); 1352 1353 } 1354 } 1355 return BCM_E_NONE; 1356 } 1357 1358 1359 1360 1361 /* 1362 * Function: 1363 * bcm_cosq_detach 1364 * Purpose: 1365 * Discard all COS schedule/mapping state. 1366 * Parameters: 1367 * unit - StrataSwitch unit number. 1368 * Returns: 1369 * BCM_E_XXX 1370 */ 1371 1372 int 1373 bcm_hu_cosq_detach(int unit, int software_state_only) 1374 { 1375 bcm_port_t port; 1376 bcm_pbmp_t port_all; 1377 int weights[8]; 1378 int cosq; 1379 1380 1381 for (cosq = 0; cosq < 8; cosq++) { 1382 weights[cosq] = 0; 1383 } 1384 1385 if (!software_state_only) 1386 { 1387 PBMP_ALL_ITER(unit, port) { 1388 if (IS_CPU_PORT(unit, port)) { 1389 continue; 1390 } 1391 1392 { 1393 /* Clear bandwidth settings on port */ 1394 for (cosq = 0; cosq < 8; cosq++) { 1395 BCM_IF_ERROR_RETURN 1396 (bcm_hu_cosq_port_bandwidth_set(unit, port, cosq, 0, 0, 0, 0)); 1397 } 1398 } 1399 } 1400 /* Clear scheduling settings on port */ 1401 cosq = 8; 1402 port_all = PBMP_ALL(unit); 1403 BCM_IF_ERROR_RETURN 1404 (bcm_hu_cosq_port_sched_set(unit, port_all, BCM_COSQ_WEIGHTED_ROUND_ROBIN, 1405 weights, 0)); 1406 /* Clear discard settings on port */ 1407 1408 1409 1410 } 1411 1412 return BCM_E_NONE; 1413 } 1414 1415 /* 1416 * Function: 1417 * bcm_hu_cosq_config_set 1418 * Purpose: 1419 * Set the number of COS queues 1420 * Parameters: 1421 * unit - Unit number. 1422 * numq - number of COS queues (1-8). 1423 * Returns: 1424 * BCM_E_XXX 1425 */ 1426 1427 int 1428 bcm_hu_cosq_config_set(int unit, int numq) 1429 { 1430 int cos, prio, ratio, remain; 1431 uint32 index; 1432 soc_mem_t mem = PORT_COS_MAPm; 1433 int entry_words = sizeof(port_cos_map_entry_t) / sizeof(uint32); 1434 bcm_pbmp_t ports; 1435 bcm_port_t port; 1436 port_cos_map_entry_t cos_map_array[HU_COS_MAP_ENTRIES_PER_SET]; 1437 void *entries[HU_COS_MAP_ENTRIES_PER_SET]; 1438 #ifdef BCM_GREYHOUND_SUPPORT 1439 static soc_mem_t wred_mems[6] = { 1440 MMU_WRED_DROP_PROFILE_GREENm, 1441 MMU_WRED_DROP_PROFILE_YELLOWm, 1442 MMU_WRED_DROP_PROFILE_REDm, 1443 MMU_WRED_MARK_PROFILE_GREENm, 1444 MMU_WRED_MARK_PROFILE_YELLOWm, 1445 MMU_WRED_MARK_PROFILE_REDm 1446 }; 1447 int ii, wred_prof_count; 1448 uint32 profile_index; 1449 mmu_wred_drop_profile_green_entry_t entry_tcp_green; 1450 mmu_wred_drop_profile_yellow_entry_t entry_tcp_yellow; 1451 mmu_wred_drop_profile_red_entry_t entry_tcp_red; 1452 mmu_wred_mark_profile_green_entry_t entry_mark_green; 1453 mmu_wred_mark_profile_yellow_entry_t entry_mark_yellow; 1454 mmu_wred_mark_profile_red_entry_t entry_mark_red; 1455 void *wred_entries[6]; 1456 #endif /* BCM_GREYHOUND_SUPPORT */ 1457 1458 /* Validate cosq num */ 1459 if (numq < 1) { 1460 return BCM_E_PARAM; 1461 } 1462 1463 if (!SOC_WARM_BOOT(unit)) { 1464 if (SOC_IS_HURRICANE(unit) || SOC_IS_HURRICANE2(unit)) { 1465 SOC_IF_ERROR_RETURN(_bcm_hu_cosq_config_set(unit, numq)); 1466 } 1467 } 1468 1469 /* Map the eight 802.1 priority levels to the active cosqs */ 1470 if (numq > 8) { 1471 numq = 8; 1472 } 1473 1474 sal_memset(cos_map_array, 0, 1475 HU_COS_MAP_ENTRIES_PER_SET * sizeof(port_cos_map_entry_t)); 1476 1477 if (_hu_cos_map_profile[unit] == NULL) { 1478 _hu_cos_map_profile[unit] = sal_alloc(sizeof(soc_profile_mem_t), 1479 "COS_MAP Profile Mem"); 1480 if (_hu_cos_map_profile[unit] == NULL) { 1481 return BCM_E_MEMORY; 1482 } 1483 soc_profile_mem_t_init(_hu_cos_map_profile[unit]); 1484 } 1485 1486 /* Create profile table cache (or re-init if it already exists) */ 1487 SOC_IF_ERROR_RETURN(soc_profile_mem_create(unit, &mem, &entry_words, 1, 1488 _hu_cos_map_profile[unit])); 1489 1490 if (SOC_WARM_BOOT(unit)) { /* Warm Boot */ 1491 int i; 1492 uint32 val; 1493 1494 /* Gather reference count for cosq map profile table */ 1495 BCM_PBMP_ASSIGN(ports, PBMP_ALL(unit)); 1496 PBMP_ITER(ports, port) { 1497 SOC_IF_ERROR_RETURN(READ_COS_MAP_SELr(unit, port, &val)); 1498 index = soc_reg_field_get(unit, COS_MAP_SELr, val, SELECTf); 1499 index *= HU_COS_MAP_ENTRIES_PER_SET; 1500 for (i = 0; i < HU_COS_MAP_ENTRIES_PER_SET; i++) { 1501 SOC_PROFILE_MEM_REFERENCE(unit, _hu_cos_map_profile[unit], 1502 index + i, 1); 1503 SOC_PROFILE_MEM_ENTRIES_PER_SET(unit, 1504 _hu_cos_map_profile[unit], 1505 index + i, 1506 HU_COS_MAP_ENTRIES_PER_SET); 1507 } 1508 #ifndef BCM_COSQ_HIGIG_MAP_DISABLE 1509 if (IS_HG_PORT(unit, port) || port == CMIC_PORT(unit)) { 1510 SOC_IF_ERROR_RETURN(READ_ICOS_MAP_SELr(unit, port, &val)); 1511 index = soc_reg_field_get(unit, ICOS_MAP_SELr, val, SELECTf); 1512 index *= HU_COS_MAP_ENTRIES_PER_SET; 1513 for (i = 0; i < HU_COS_MAP_ENTRIES_PER_SET; i++) { 1514 SOC_PROFILE_MEM_REFERENCE(unit, _hu_cos_map_profile[unit], 1515 index + i, 1); 1516 SOC_PROFILE_MEM_ENTRIES_PER_SET(unit, 1517 _hu_cos_map_profile[unit], 1518 index + i, 1519 HU_COS_MAP_ENTRIES_PER_SET); 1520 } 1521 } 1522 #endif /* BCM_COSQ_HIGIG_MAP_DISABLE */ 1523 } 1524 1525 _hu_num_cosq[unit] = numq; 1526 1527 return BCM_E_NONE; 1528 } 1529 1530 /* Cold Boot */ 1531 ratio = 8 / numq; 1532 remain = 8 % numq; 1533 cos = 0; 1534 for (prio = 0; prio < 8; prio++) { 1535 soc_mem_field32_set(unit, PORT_COS_MAPm, 1536 &cos_map_array[prio], COSf, cos); 1537 if (soc_mem_field_valid(unit,PORT_COS_MAPm,HG_COSf)) { 1538 soc_mem_field32_set(unit, PORT_COS_MAPm, 1539 &cos_map_array[prio], HG_COSf, 0); 1540 } 1541 1542 if ((prio + 1) == (((cos + 1) * ratio) + 1543 ((remain < (numq - cos)) ? 0 : 1544 (remain - (numq - cos) + 1)))) { 1545 cos++; 1546 } 1547 entries[prio] = (void *) &cos_map_array[prio]; 1548 } 1549 1550 /* Map remaining internal priority levels to highest priority cosq */ 1551 cos = numq - 1; 1552 for (prio = 8; prio < 16; prio++) { 1553 soc_mem_field32_set(unit, PORT_COS_MAPm, 1554 &cos_map_array[prio], COSf, cos); 1555 if (soc_mem_field_valid(unit,PORT_COS_MAPm,HG_COSf)) { 1556 soc_mem_field32_set(unit, PORT_COS_MAPm, 1557 &cos_map_array[prio], HG_COSf, 0); 1558 } 1559 entries[prio] = (void *) &cos_map_array[prio]; 1560 } 1561 1562 /* Map internal priority levels to CPU CoS queues */ 1563 BCM_IF_ERROR_RETURN(_bcm_esw_cpu_cosq_mapping_default_set(unit, numq)); 1564 1565 /* Add a profile mem entry for each port */ 1566 BCM_PBMP_ASSIGN(ports, PBMP_ALL(unit)); 1567 PBMP_ITER(ports, port) { 1568 SOC_IF_ERROR_RETURN 1569 (soc_profile_mem_add(unit, _hu_cos_map_profile[unit], 1570 (void *) &entries, 1571 HU_COS_MAP_ENTRIES_PER_SET, &index)); 1572 SOC_IF_ERROR_RETURN(soc_reg_field32_modify(unit, COS_MAP_SELr, port, 1573 SELECTf, (index / HU_COS_MAP_ENTRIES_PER_SET))); 1574 #ifndef BCM_COSQ_HIGIG_MAP_DISABLE 1575 if (IS_HG_PORT(unit, port) || port == CMIC_PORT(unit)) { 1576 SOC_IF_ERROR_RETURN 1577 (soc_profile_mem_add(unit, _hu_cos_map_profile[unit], 1578 (void *) &entries, 1579 HU_COS_MAP_ENTRIES_PER_SET, &index)); 1580 SOC_IF_ERROR_RETURN(soc_reg_field32_modify(unit, ICOS_MAP_SELr, port, 1581 SELECTf, (index / HU_COS_MAP_ENTRIES_PER_SET))); 1582 } 1583 #endif 1584 } 1585 1586 #ifdef BCM_COSQ_HIGIG_MAP_DISABLE 1587 /* identity mapping for higig ports */ 1588 1589 /* map prio0->cos0, prio1->cos1, ... , prio7->cos7 */ 1590 for (prio = 0; prio < 8; prio++) { 1591 soc_mem_field32_set(unit, PORT_COS_MAPm, 1592 &cos_map_array[prio], COSf, prio); 1593 if (soc_mem_field_valid(unit,PORT_COS_MAPm,HG_COSf)) { 1594 soc_mem_field32_set(unit, PORT_COS_MAPm, 1595 &cos_map_array[prio], HG_COSf, 0); 1596 } 1597 } 1598 /* Map remaining internal priority levels to highest priority cosq */ 1599 for (prio = 8; prio < 16; prio++) { 1600 soc_mem_field32_set(unit, PORT_COS_MAPm, 1601 &cos_map_array[prio], COSf, 7); 1602 if (soc_mem_field_valid(unit,PORT_COS_MAPm,HG_COSf)) { 1603 soc_mem_field32_set(unit, PORT_COS_MAPm, 1604 &cos_map_array[prio], HG_COSf, 0); 1605 } 1606 } 1607 PBMP_ITER(ports, port) { 1608 if (IS_HG_PORT(unit, port) || port == CMIC_PORT(unit)) { 1609 SOC_IF_ERROR_RETURN 1610 (soc_profile_mem_add(unit, _hu_cos_map_profile[unit], 1611 (void *) &entries, 1612 HU_COS_MAP_ENTRIES_PER_SET, &index)); 1613 soc_reg_field32_modify(unit, ICOS_MAP_SELr, port, 1614 SELECTf, (index / HU_COS_MAP_ENTRIES_PER_SET)); 1615 } 1616 } 1617 #endif 1618 1619 _hu_num_cosq[unit] = numq; 1620 1621 #if defined(BCM_GREYHOUND_SUPPORT) 1622 if (soc_feature(unit, soc_feature_discard_ability)) { 1623 /* Add default entries for MMU_WRED_DROP_CURVE_PROFILE_x memory profile */ 1624 sal_memset(&entry_tcp_green, 0, sizeof(entry_tcp_green)); 1625 sal_memset(&entry_tcp_yellow,0, sizeof(entry_tcp_yellow)); 1626 sal_memset(&entry_tcp_red, 0, sizeof(entry_tcp_red)); 1627 sal_memset(&entry_mark_green, 0, sizeof(entry_mark_green)); 1628 sal_memset(&entry_mark_yellow, 0, sizeof(entry_mark_yellow)); 1629 sal_memset(&entry_mark_red, 0, sizeof(entry_mark_red)); 1630 wred_entries[0] = &entry_tcp_green; 1631 wred_entries[1] = &entry_tcp_yellow; 1632 wred_entries[2] = &entry_tcp_red; 1633 wred_entries[3] = &entry_mark_green; 1634 wred_entries[4] = &entry_mark_yellow; 1635 wred_entries[5] = &entry_mark_red; 1636 for (ii = 0; ii < 6; ii++) { 1637 soc_mem_field32_set(unit, wred_mems[ii], wred_entries[ii], 1638 MIN_THDf, GH_CELL_FIELD_MAX); 1639 soc_mem_field32_set(unit, wred_mems[ii], wred_entries[ii], 1640 MAX_THDf, GH_CELL_FIELD_MAX); 1641 } 1642 profile_index = 0xffffffff; 1643 wred_prof_count = soc_mem_index_count(unit, MMU_WRED_CONFIGm); 1644 while(wred_prof_count) { 1645 if (profile_index == 0xffffffff) { 1646 BCM_IF_ERROR_RETURN 1647 (soc_profile_mem_add(unit, 1648 _bcm_gh_wred_profile[unit], 1649 wred_entries, 1, &profile_index)); 1650 } else { 1651 BCM_IF_ERROR_RETURN 1652 (soc_profile_mem_reference(unit, 1653 _bcm_gh_wred_profile[unit], 1654 profile_index, 0)); 1655 } 1656 wred_prof_count -= 1; 1657 } 1658 1659 BCM_IF_ERROR_RETURN( 1660 _bcm_esw_ecn_init(unit)); 1661 1662 } 1663 #endif /* BCM_GREYHOUND_SUPPORT */ 1664 1665 1666 return BCM_E_NONE; 1667 } 1668 1669 /* 1670 * Function: 1671 * bcm_cosq_config_get 1672 * Purpose: 1673 * Get the number of cos queues 1674 * Parameters: 1675 * unit - StrataSwitch unit number. 1676 * numq - (Output) number of cosq 1677 * Returns: 1678 * BCM_E_XXX 1679 */ 1680 1681 int 1682 bcm_hu_cosq_config_get(int unit, int *numq) 1683 { 1684 if (_hu_num_cosq[unit] == 0) { 1685 return BCM_E_INIT; 1686 } 1687 1688 if (numq != NULL) { 1689 *numq = _hu_num_cosq[unit]; 1690 } 1691 1692 return BCM_E_NONE; 1693 } 1694 1695 int 1696 bcm_hu_cosq_discard_set(int unit, uint32 flags) 1697 { 1698 return BCM_E_UNAVAIL; 1699 } 1700 1701 int 1702 bcm_hu_cosq_discard_get(int unit, uint32* flags) 1703 { 1704 return BCM_E_UNAVAIL; 1705 } 1706 1707 int 1708 bcm_hu_cosq_gport_discard_set(int unit, bcm_gport_t port, bcm_cos_queue_t cosq, 1709 bcm_cosq_gport_discard_t *discard) 1710 { 1711 return BCM_E_UNAVAIL; 1712 } 1713 1714 int 1715 bcm_hu_cosq_gport_discard_get(int unit, bcm_gport_t port, bcm_cos_queue_t cosq, 1716 bcm_cosq_gport_discard_t *discard) 1717 { 1718 return BCM_E_UNAVAIL; 1719 } 1720 1721 1722 int 1723 bcm_hu_cosq_discard_port_set(int unit, bcm_port_t port, 1724 bcm_cos_queue_t cosq, 1725 uint32 color, 1726 int drop_start, 1727 int drop_slope, 1728 int average_time) 1729 { 1730 bcm_port_t local_port; 1731 bcm_pbmp_t pbmp; 1732 int i, cosq_start, num_cosq; 1733 uint32 min_thresh, n; 1734 uint32 rval, encoding; 1735 soc_reg_t reg; 1736 soc_field_t fld; 1737 1738 if (drop_start < 0 || drop_start > 100 || drop_slope > 0) { 1739 return BCM_E_PARAM; 1740 } 1741 1742 if (BCM_GPORT_IS_SET(port)) { 1743 BCM_IF_ERROR_RETURN(bcm_esw_port_local_get(unit, port, &local_port)); 1744 BCM_PBMP_PORT_SET(pbmp, local_port); 1745 } else { 1746 if (port == -1) { 1747 BCM_PBMP_ASSIGN(pbmp, PBMP_ALL(unit)); 1748 } else if (!SOC_PORT_VALID(unit, port)) { 1749 return BCM_E_PORT; 1750 } else { 1751 BCM_PBMP_PORT_SET(pbmp, port); 1752 } 1753 } 1754 1755 if (cosq < -1 || cosq >= _hu_num_cosq[unit]) { 1756 return BCM_E_PARAM; 1757 } else if (cosq == -1) { 1758 cosq_start = 0; 1759 num_cosq = _hu_num_cosq[unit]; 1760 } else { 1761 cosq_start = cosq; 1762 num_cosq = 1; 1763 } 1764 1765 BCM_PBMP_ITER(pbmp, local_port) { 1766 for (i = cosq_start; i < (cosq_start + num_cosq); i++) { 1767 /* Get the start point as a function of the HOL limit */ 1768 SOC_IF_ERROR_RETURN 1769 (READ_HOLCOSPKTSETLIMITr(unit, local_port, i, &rval)); 1770 n = soc_reg_field_get(unit, HOLCOSPKTSETLIMITr, rval, 1771 PKTSETLIMITf); 1772 min_thresh = drop_start * n / 100; 1773 1774 /* Set the drop rate depending on the color */ 1775 if (color == BCM_COSQ_DISCARD_COLOR_GREEN) { 1776 reg = CNG1COSDROPRATEr; 1777 } else { 1778 reg = CNG0COSDROPRATEr; 1779 } 1780 BCM_IF_ERROR_RETURN( 1781 soc_reg32_get(unit, reg, local_port, i, &rval)); 1782 1783 if (SOC_IS_HURRICANE2(unit)) { 1784 encoding = _bcm_hu2_api_val_to_hw_drop_prob(-1 * drop_slope); 1785 } else { 1786 encoding = _bcm_hu_api_val_to_hw_drop_prob(-1 * drop_slope); 1787 } 1788 1789 soc_reg_field_set(unit, reg, &rval, DROPRATEf, encoding); 1790 BCM_IF_ERROR_RETURN( 1791 soc_reg32_set(unit, reg, local_port, i, rval)); 1792 1793 /* Enable simple RED for the (port, cos) pair */ 1794 BCM_IF_ERROR_RETURN 1795 (soc_reg_field32_modify(unit, SIMPLEREDCONFIGr, local_port, 1796 _hu_cosfld[i], 1)); 1797 /* Set the drop threshold depending on the color */ 1798 if (color == BCM_COSQ_DISCARD_COLOR_GREEN) { 1799 reg = CNGCOSPKTLIMIT1r; 1800 fld = CNGPKTSETLIMIT1f; 1801 } else { 1802 reg = CNGCOSPKTLIMIT0r; 1803 fld = CNGPKTSETLIMIT0f; 1804 } 1805 soc_reg_field_set(unit, reg, &rval, fld, min_thresh); 1806 BCM_IF_ERROR_RETURN( 1807 soc_reg32_set(unit, reg, local_port, i, rval)); 1808 } 1809 } 1810 1811 return BCM_E_NONE; 1812 } 1813 1814 int 1815 bcm_hu_cosq_discard_port_get(int unit, bcm_port_t port, 1816 bcm_cos_queue_t cosq, 1817 uint32 color, 1818 int *drop_start, 1819 int *drop_slope, 1820 int *average_time) 1821 { 1822 bcm_port_t local_port; 1823 bcm_pbmp_t pbmp; 1824 uint32 rval, n; 1825 1826 if (BCM_GPORT_IS_SET(port)) { 1827 BCM_IF_ERROR_RETURN(bcm_esw_port_local_get(unit, port, &local_port)); 1828 BCM_PBMP_PORT_SET(pbmp, local_port); 1829 } else { 1830 if (port == -1) { 1831 BCM_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit)); 1832 } else if (!SOC_PORT_VALID(unit, port)) { 1833 return BCM_E_PORT; 1834 } else { 1835 BCM_PBMP_PORT_SET(pbmp, port); 1836 } 1837 } 1838 if (cosq < -1 || cosq >= _hu_num_cosq[unit]) { 1839 return BCM_E_PARAM; 1840 } 1841 1842 BCM_PBMP_ITER(pbmp, local_port) { 1843 /* Get the total HOL limit first */ 1844 BCM_IF_ERROR_RETURN 1845 (READ_HOLCOSPKTSETLIMITr(unit, local_port, 1846 cosq == -1 ? 0 : cosq, &rval)); 1847 n = soc_reg_field_get(unit, HOLCOSPKTSETLIMITr, rval, PKTSETLIMITf); 1848 1849 /* Get the simple RED mode */ 1850 BCM_IF_ERROR_RETURN(READ_SIMPLEREDCONFIGr(unit, local_port, &rval)); 1851 if (soc_reg_field_get(unit, SIMPLEREDCONFIGr, rval, 1852 cosq == -1 ? _hu_cosfld[0] : _hu_cosfld[cosq])) { 1853 if (color == BCM_COSQ_DISCARD_COLOR_GREEN) { 1854 BCM_IF_ERROR_RETURN 1855 (READ_CNGCOSPKTLIMIT1r(unit, local_port, 1856 cosq == -1 ? 0 : cosq, &rval)); 1857 *drop_start = soc_reg_field_get(unit, CNGCOSPKTLIMIT1r, rval, 1858 CNGPKTSETLIMIT1f) * 100 / n; 1859 BCM_IF_ERROR_RETURN 1860 (READ_CNG1COSDROPRATEr(unit, local_port, 1861 cosq == -1 ? 0 : cosq, &rval)); 1862 if (SOC_IS_HURRICANE2(unit)) { 1863 *drop_slope = -1 * _bcm_hu2_hw_drop_prob_to_api_val[rval]; 1864 } else { 1865 *drop_slope = -1 * _bcm_hu_hw_drop_prob_to_api_val[rval]; 1866 } 1867 } else { 1868 BCM_IF_ERROR_RETURN 1869 (READ_CNGCOSPKTLIMIT0r(unit, local_port, 1870 cosq == -1 ? 0 : cosq, &rval)); 1871 *drop_start = soc_reg_field_get(unit, CNGCOSPKTLIMIT0r, rval, 1872 CNGPKTSETLIMIT0f) * 100 / n; 1873 BCM_IF_ERROR_RETURN 1874 (READ_CNG0COSDROPRATEr(unit, local_port, 1875 cosq == -1 ? 0 : cosq, &rval)); 1876 if (SOC_IS_HURRICANE2(unit)) { 1877 *drop_slope = -1 * _bcm_hu2_hw_drop_prob_to_api_val[rval]; 1878 } else { 1879 *drop_slope = -1 * _bcm_hu_hw_drop_prob_to_api_val[rval]; 1880 } 1881 } 1882 } 1883 break; 1884 } 1885 return BCM_E_NONE; 1886 } 1887 1888 #if defined(BCM_GREYHOUND_SUPPORT) 1889 1890 /* 1891 * Convert HW drop probability to percent value 1892 */ 1893 STATIC int 1894 _bcm_gh_hw_drop_prob_to_percent[] = { 1895 0, /* 0 */ 1896 1, /* 1 */ 1897 2, /* 2 */ 1898 3, /* 3 */ 1899 4, /* 4 */ 1900 5, /* 5 */ 1901 6, /* 6 */ 1902 7, /* 7 */ 1903 8, /* 8 */ 1904 9, /* 9 */ 1905 10, /* 10 */ 1906 25, /* 11 */ 1907 50, /* 12 */ 1908 75, /* 13 */ 1909 100, /* 14 */ 1910 -1 /* 15 */ 1911 }; 1912 1913 STATIC int 1914 _bcm_gh_percent_to_drop_prob(int percent) 1915 { 1916 int i; 1917 1918 for (i = 14; i > 0 ; i--) { 1919 if (percent >= _bcm_gh_hw_drop_prob_to_percent[i]) { 1920 break; 1921 } 1922 } 1923 return i; 1924 } 1925 1926 STATIC int 1927 _bcm_gh_drop_prob_to_percent(int drop_prob) { 1928 return (_bcm_gh_hw_drop_prob_to_percent[drop_prob]); 1929 } 1930 1931 /* 1932 * index: degree, value: contangent(degree) * 100 1933 * max value is 0x3fff (14-bit) at 0 degree 1934 */ 1935 STATIC int 1936 _bcm_gh_cotangent_lookup_table[] = 1937 { 1938 /* 0.. 5 */ 16383, 5728, 2863, 1908, 1430, 1143, 1939 /* 6..11 */ 951, 814, 711, 631, 567, 514, 1940 /* 12..17 */ 470, 433, 401, 373, 348, 327, 1941 /* 18..23 */ 307, 290, 274, 260, 247, 235, 1942 /* 24..29 */ 224, 214, 205, 196, 188, 180, 1943 /* 30..35 */ 173, 166, 160, 153, 148, 142, 1944 /* 36..41 */ 137, 132, 127, 123, 119, 115, 1945 /* 42..47 */ 111, 107, 103, 100, 96, 93, 1946 /* 48..53 */ 90, 86, 83, 80, 78, 75, 1947 /* 54..59 */ 72, 70, 67, 64, 62, 60, 1948 /* 60..65 */ 57, 55, 53, 50, 48, 46, 1949 /* 66..71 */ 44, 42, 40, 38, 36, 34, 1950 /* 72..77 */ 32, 30, 28, 26, 24, 23, 1951 /* 78..83 */ 21, 19, 17, 15, 14, 12, 1952 /* 84..89 */ 10, 8, 6, 5, 3, 1, 1953 /* 90 */ 0 1954 }; 1955 1956 /* 1957 * Given a slope (angle in degrees) from 0 to 90, return the number of cells 1958 * in the range from 0% drop probability to 100% drop probability. 1959 */ 1960 STATIC int 1961 _bcm_gh_angle_to_cells(int angle) 1962 { 1963 return (_bcm_gh_cotangent_lookup_table[angle]); 1964 } 1965 1966 /* 1967 * Given a number of packets in the range from 0% drop probability 1968 * to 100% drop probability, return the slope (angle in degrees). 1969 */ 1970 STATIC int 1971 _bcm_gh_cells_to_angle(int packets) 1972 { 1973 int angle; 1974 1975 for (angle = 90; angle >= 0 ; angle--) { 1976 if (packets <= _bcm_gh_cotangent_lookup_table[angle]) { 1977 break; 1978 } 1979 } 1980 return angle; 1981 } 1982 1983 /* 1984 * Function: 1985 * _bcm_gh_cosq_wred_set 1986 * Purpose: 1987 * Configure queue WRED setting 1988 * Parameters: 1989 * unit - (IN) unit number 1990 * port - (IN) port number or GPORT identifier 1991 * cosq - (IN) COS queue number 1992 * flags - (IN) BCM_COSQ_DISCARD_XXX 1993 * min_thresh - (IN) 1994 * max_thresh - (IN) 1995 * drop_probablity - (IN) 1996 * gain - (IN) 1997 * ignore_enable_flags - (IN) 1998 * Returns: 1999 * BCM_E_XXX 2000 * Notes: 2001 * If port is any form of local port, cosq is the hardware queue index. 2002 */ 2003 STATIC int 2004 _bcm_gh_cosq_wred_set(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 2005 uint32 flags, uint32 min_thresh, uint32 max_thresh, 2006 int drop_probability, int gain, int ignore_enable_flags, 2007 uint32 lflags) 2008 { 2009 int index; 2010 uint32 profile_index, old_profile_index; 2011 mmu_wred_drop_profile_green_entry_t entry_tcp_green; 2012 mmu_wred_drop_profile_yellow_entry_t entry_tcp_yellow; 2013 mmu_wred_drop_profile_red_entry_t entry_tcp_red; 2014 mmu_wred_mark_profile_green_entry_t entry_mark_green; 2015 mmu_wred_mark_profile_yellow_entry_t entry_mark_yellow; 2016 mmu_wred_mark_profile_red_entry_t entry_mark_red; 2017 mmu_wred_config_entry_t qentry; 2018 void *entries[6]; 2019 soc_mem_t mems[6]; 2020 int rate, i, exists = 0; 2021 static soc_mem_t wred_mems[6] = { 2022 MMU_WRED_DROP_PROFILE_GREENm, 2023 MMU_WRED_DROP_PROFILE_YELLOWm, 2024 MMU_WRED_DROP_PROFILE_REDm, 2025 MMU_WRED_MARK_PROFILE_GREENm, 2026 MMU_WRED_MARK_PROFILE_YELLOWm, 2027 MMU_WRED_MARK_PROFILE_REDm 2028 }; 2029 2030 /* 2031 * MEM_ADDR[7:0]={PORT_ID[4:0], QUEUE_ID[2:0]} 2032 * PORT_ID[4:0] = 0, PORT 2, 2033 * PORT_ID[4:0] = 1, PORT 3, 2034 * ... 2035 * PORT_ID[4:0] = 27, PORT 29, 2036 * PORT_ID[4:0] = 28, Invalid, 2037 */ 2038 if (!SOC_PORT_VALID(unit, port) || (CMIC_PORT(unit) == port)) { 2039 return BCM_E_PORT; 2040 } 2041 2042 index = (((port - 2) & 0x1f) << 3) | (cosq & 7); 2043 2044 if (index < 0) { 2045 return BCM_E_PARAM; 2046 } 2047 2048 BCM_IF_ERROR_RETURN 2049 (soc_mem_read(unit, MMU_WRED_CONFIGm, SOC_BLOCK_ALL, index, &qentry)); 2050 2051 old_profile_index = 0xffffffff; 2052 2053 if (flags & BCM_COSQ_DISCARD_NONTCP) { 2054 /* Greyhound doesnot support non-responsive dropping */ 2055 return BCM_E_UNAVAIL; 2056 } 2057 2058 if (flags & (BCM_COSQ_DISCARD_TCP | BCM_COSQ_DISCARD_COLOR_ALL | 2059 BCM_COSQ_DISCARD_MARK_CONGESTION)) { 2060 old_profile_index = soc_mem_field32_get(unit, MMU_WRED_CONFIGm, 2061 &qentry, PROFILE_INDEXf); 2062 entries[0] = &entry_tcp_green; 2063 entries[1] = &entry_tcp_yellow; 2064 entries[2] = &entry_tcp_red; 2065 entries[3] = &entry_mark_green; 2066 entries[4] = &entry_mark_yellow; 2067 entries[5] = &entry_mark_red; 2068 BCM_IF_ERROR_RETURN 2069 (soc_profile_mem_get(unit, _bcm_gh_wred_profile[unit], 2070 old_profile_index, 1, entries)); 2071 for (i = 0; i < 6; i++) { 2072 mems[i] = INVALIDm; 2073 } 2074 if ((flags & BCM_COSQ_DISCARD_TCP) || 2075 !(flags & BCM_COSQ_DISCARD_MARK_CONGESTION)) { 2076 if (flags & BCM_COSQ_DISCARD_COLOR_GREEN) { 2077 mems[0] = MMU_WRED_DROP_PROFILE_GREENm; 2078 } 2079 if (flags & BCM_COSQ_DISCARD_COLOR_YELLOW) { 2080 mems[1] = MMU_WRED_DROP_PROFILE_YELLOWm; 2081 } 2082 if (flags & BCM_COSQ_DISCARD_COLOR_RED) { 2083 mems[2] = MMU_WRED_DROP_PROFILE_REDm; 2084 } 2085 } 2086 if (flags & BCM_COSQ_DISCARD_MARK_CONGESTION) { 2087 if (flags & BCM_COSQ_DISCARD_COLOR_GREEN) { 2088 mems[3] = MMU_WRED_MARK_PROFILE_GREENm; 2089 } 2090 if (flags & BCM_COSQ_DISCARD_COLOR_YELLOW) { 2091 mems[4] = MMU_WRED_MARK_PROFILE_YELLOWm; 2092 } 2093 if (flags & BCM_COSQ_DISCARD_COLOR_RED) { 2094 mems[5] = MMU_WRED_MARK_PROFILE_REDm; 2095 } 2096 } 2097 rate = _bcm_gh_percent_to_drop_prob(drop_probability); 2098 for (i = 0; i < 6; i++) { 2099 exists = 0; 2100 if ((soc_mem_field32_get(unit, wred_mems[i], entries[i], 2101 MIN_THDf) != GH_CELL_FIELD_MAX) && (mems[i] == INVALIDm)) { 2102 mems[i] = wred_mems[i]; 2103 exists = 1; 2104 } else { 2105 soc_mem_field32_set(unit, wred_mems[i], entries[i], 2106 MIN_THDf, (mems[i] == INVALIDm) ? 2107 GH_CELL_FIELD_MAX : min_thresh); 2108 } 2109 2110 if ((soc_mem_field32_get(unit, wred_mems[i], entries[i], 2111 MAX_THDf) != GH_CELL_FIELD_MAX) && 2112 ((mems[i] == INVALIDm) || exists)) { 2113 mems[i] = wred_mems[i]; 2114 exists = 1; 2115 } else { 2116 soc_mem_field32_set(unit, wred_mems[i], entries[i], 2117 MAX_THDf, (mems[i] == INVALIDm) ? 2118 GH_CELL_FIELD_MAX :max_thresh); 2119 } 2120 2121 if (!exists) { 2122 if (soc_mem_field_valid(unit, wred_mems[i], 2123 MAX_DROP_RATEf)) { 2124 soc_mem_field32_set(unit, wred_mems[i], entries[i], 2125 MAX_DROP_RATEf, (mems[i] == INVALIDm) ? 0 : rate); 2126 } else if (soc_mem_field_valid(unit, wred_mems[i], 2127 MAX_MARK_RATEf)) { 2128 soc_mem_field32_set(unit, wred_mems[i], entries[i], 2129 MAX_MARK_RATEf, (mems[i] == INVALIDm) ? 0 : rate); 2130 } 2131 } 2132 } 2133 BCM_IF_ERROR_RETURN 2134 (soc_profile_mem_add(unit, _bcm_gh_wred_profile[unit], 2135 entries, 1, &profile_index)); 2136 soc_mem_field32_set(unit, MMU_WRED_CONFIGm, 2137 &qentry, PROFILE_INDEXf, profile_index); 2138 soc_mem_field32_set(unit, MMU_WRED_CONFIGm, &qentry, WEIGHTf, gain); 2139 } 2140 /* Some APIs only modify profiles */ 2141 if (!ignore_enable_flags) { 2142 soc_mem_field32_set(unit, MMU_WRED_CONFIGm, &qentry, CAP_AVGf, 2143 flags & BCM_COSQ_DISCARD_CAP_AVERAGE ? 1 : 0); 2144 soc_mem_field32_set(unit, MMU_WRED_CONFIGm, &qentry, WRED_ENf, 2145 flags & BCM_COSQ_DISCARD_ENABLE ? 1 : 0); 2146 soc_mem_field32_set(unit, MMU_WRED_CONFIGm, &qentry, ECN_MARKING_ENf, 2147 flags & BCM_COSQ_DISCARD_MARK_CONGESTION ? 1 : 0); 2148 } 2149 2150 BCM_IF_ERROR_RETURN( 2151 soc_mem_write(unit, MMU_WRED_CONFIGm, MEM_BLOCK_ALL, index, &qentry)); 2152 2153 if (old_profile_index != 0xffffffff) { 2154 SOC_IF_ERROR_RETURN 2155 (soc_profile_mem_delete(unit, _bcm_gh_wred_profile[unit], 2156 old_profile_index)); 2157 } 2158 2159 return BCM_E_NONE; 2160 } 2161 2162 /* 2163 * Function: 2164 * _bcm_gh_cosq_wred_get 2165 * Purpose: 2166 * Get queue WRED setting 2167 * Parameters: 2168 * unit - (IN) unit number 2169 * port - (IN) port number or GPORT identifier 2170 * cosq - (IN) COS queue number 2171 * flags - (IN/OUT) BCM_COSQ_DISCARD_XXX 2172 * min_thresh - (OUT) 2173 * max_thresh - (OUT) 2174 * drop_probablity - (OUT) 2175 * gain - (OUT) 2176 * Returns: 2177 * BCM_E_XXX 2178 * Notes: 2179 * If port is any form of local port, cosq is the hardware queue index. 2180 */ 2181 STATIC int 2182 _bcm_gh_cosq_wred_get(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 2183 uint32 *flags, uint32 *min_thresh, uint32 *max_thresh, 2184 int *drop_probability, int *gain, uint32 lflags) 2185 { 2186 int index, profile_index; 2187 mmu_wred_drop_profile_green_entry_t entry_tcp_green; 2188 mmu_wred_drop_profile_yellow_entry_t entry_tcp_yellow; 2189 mmu_wred_drop_profile_red_entry_t entry_tcp_red; 2190 mmu_wred_mark_profile_green_entry_t entry_mark_green; 2191 mmu_wred_mark_profile_yellow_entry_t entry_mark_yellow; 2192 mmu_wred_mark_profile_red_entry_t entry_mark_red; 2193 void *entries[6]; 2194 void *entry_p = NULL; 2195 soc_mem_t mem = INVALIDm; 2196 mmu_wred_config_entry_t qentry; 2197 int rate = 0; 2198 2199 /* 2200 * MEM_ADDR[7:0]={PORT_ID[4:0], QUEUE_ID[2:0]} 2201 * PORT_ID[4:0] = 0, PORT 2, 2202 * PORT_ID[4:0] = 1, PORT 3, 2203 * ... 2204 * PORT_ID[4:0] = 27, PORT 29, 2205 * PORT_ID[4:0] = 28, Invalid, 2206 */ 2207 if (!SOC_PORT_VALID(unit, port) || (CMIC_PORT(unit) == port)) { 2208 return BCM_E_PORT; 2209 } 2210 index = (((port - 2) & 0x1f) << 3) | (cosq & 7); 2211 2212 2213 BCM_IF_ERROR_RETURN 2214 (soc_mem_read(unit, MMU_WRED_CONFIGm, MEM_BLOCK_ALL, index, &qentry)); 2215 profile_index = soc_mem_field32_get(unit, MMU_WRED_CONFIGm, 2216 &qentry, PROFILE_INDEXf); 2217 2218 if (*flags & BCM_COSQ_DISCARD_MARK_CONGESTION) { 2219 if (*flags & BCM_COSQ_DISCARD_COLOR_GREEN) { 2220 mem = MMU_WRED_MARK_PROFILE_GREENm; 2221 entry_p = &entry_mark_green; 2222 } else if (*flags & BCM_COSQ_DISCARD_COLOR_YELLOW) { 2223 mem = MMU_WRED_MARK_PROFILE_YELLOWm; 2224 entry_p = &entry_mark_yellow; 2225 } else if (*flags & BCM_COSQ_DISCARD_COLOR_RED) { 2226 mem = MMU_WRED_MARK_PROFILE_REDm; 2227 entry_p = &entry_mark_red; 2228 } else { 2229 mem = MMU_WRED_MARK_PROFILE_GREENm; 2230 entry_p = &entry_mark_green; 2231 } 2232 } else { 2233 if (*flags & BCM_COSQ_DISCARD_COLOR_GREEN) { 2234 mem = MMU_WRED_DROP_PROFILE_GREENm; 2235 entry_p = &entry_tcp_green; 2236 } else if (*flags & BCM_COSQ_DISCARD_COLOR_YELLOW) { 2237 mem = MMU_WRED_DROP_PROFILE_YELLOWm; 2238 entry_p = &entry_tcp_yellow; 2239 } else if (*flags & BCM_COSQ_DISCARD_COLOR_RED) { 2240 mem = MMU_WRED_DROP_PROFILE_REDm; 2241 entry_p = &entry_tcp_red; 2242 } else { 2243 mem = MMU_WRED_DROP_PROFILE_GREENm; 2244 entry_p = &entry_tcp_green; 2245 } 2246 } 2247 2248 entries[0] = &entry_tcp_green; 2249 entries[1] = &entry_tcp_yellow; 2250 entries[2] = &entry_tcp_red; 2251 entries[3] = &entry_mark_green; 2252 entries[4] = &entry_mark_yellow; 2253 entries[5] = &entry_mark_red; 2254 BCM_IF_ERROR_RETURN 2255 (soc_profile_mem_get(unit, _bcm_gh_wred_profile[unit], 2256 profile_index, 1, entries)); 2257 if (min_thresh != NULL) { 2258 *min_thresh = soc_mem_field32_get(unit, mem, entry_p, MIN_THDf); 2259 } 2260 if (max_thresh != NULL) { 2261 *max_thresh = soc_mem_field32_get(unit, mem, entry_p, MAX_THDf); 2262 } 2263 if (drop_probability != NULL) { 2264 if (soc_mem_field_valid(unit, mem, MAX_DROP_RATEf)) { 2265 rate = soc_mem_field32_get(unit, mem, entry_p, MAX_DROP_RATEf); 2266 } else if (soc_mem_field_valid(unit, mem, MAX_MARK_RATEf)) { 2267 rate = soc_mem_field32_get(unit, mem, entry_p, MAX_MARK_RATEf); 2268 } 2269 *drop_probability = _bcm_gh_drop_prob_to_percent(rate); 2270 } 2271 2272 if (gain) { 2273 *gain = soc_mem_field32_get(unit, MMU_WRED_CONFIGm, &qentry, WEIGHTf); 2274 } 2275 2276 *flags &= ~(BCM_COSQ_DISCARD_CAP_AVERAGE | BCM_COSQ_DISCARD_ENABLE); 2277 if (soc_mem_field32_get(unit, MMU_WRED_CONFIGm, &qentry, CAP_AVGf)) { 2278 *flags |= BCM_COSQ_DISCARD_CAP_AVERAGE; 2279 } 2280 if (soc_mem_field32_get(unit, MMU_WRED_CONFIGm, &qentry, WRED_ENf)) { 2281 *flags |= BCM_COSQ_DISCARD_ENABLE; 2282 } 2283 if (soc_mem_field32_get(unit, MMU_WRED_CONFIGm, &qentry, ECN_MARKING_ENf)) { 2284 *flags |= BCM_COSQ_DISCARD_MARK_CONGESTION; 2285 } 2286 return BCM_E_NONE; 2287 } 2288 2289 2290 int 2291 bcm_gh_cosq_discard_set(int unit, uint32 flags) 2292 { 2293 bcm_port_t port; 2294 int numq, i; 2295 2296 if (!soc_feature(unit, soc_feature_discard_ability)) { 2297 return BCM_E_UNAVAIL; 2298 } 2299 2300 flags &= ~(BCM_COSQ_DISCARD_NONTCP | BCM_COSQ_DISCARD_COLOR_ALL); 2301 2302 numq = _hu_num_cosq[unit]; 2303 PBMP_PORT_ITER(unit, port) { 2304 for (i = 0; i < numq; i++) { 2305 BCM_IF_ERROR_RETURN 2306 (_bcm_gh_cosq_wred_set(unit, port, i, flags, 0, 0, 0, 0, 2307 FALSE, BCM_COSQ_DISCARD_PORT)); 2308 } 2309 } 2310 2311 return BCM_E_NONE; 2312 } 2313 2314 int 2315 bcm_gh_cosq_discard_get(int unit, uint32 *flags) 2316 { 2317 bcm_port_t port; 2318 2319 if (!soc_feature(unit, soc_feature_discard_ability)) { 2320 return BCM_E_UNAVAIL; 2321 } 2322 2323 PBMP_PORT_ITER(unit, port) { 2324 *flags = 0; 2325 return _bcm_gh_cosq_wred_get(unit, port, 0, flags, NULL, NULL, NULL, 2326 NULL, BCM_COSQ_DISCARD_PORT); 2327 } 2328 2329 return BCM_E_NOT_FOUND; 2330 } 2331 2332 2333 /* 2334 * Function: 2335 * bcm_gh_cosq_gport_discard_set 2336 * Purpose: 2337 * Configure port WRED setting 2338 * Parameters: 2339 * unit - (IN) unit number 2340 * port - (IN) GPORT identifier 2341 * cosq - (IN) COS queue to configure, -1 for all COS queues 2342 * discard - (IN) discard settings 2343 * Returns: 2344 * BCM_E_XXX 2345 */ 2346 2347 int 2348 bcm_gh_cosq_gport_discard_set(int unit, bcm_gport_t port, bcm_cos_queue_t cosq, 2349 bcm_cosq_gport_discard_t *discard) 2350 { 2351 int numq, i; 2352 uint32 min_thresh, max_thresh; 2353 int cell_size, cell_field_max; 2354 bcm_port_t local_port; 2355 bcm_pbmp_t pbmp; 2356 2357 if (!soc_feature(unit, soc_feature_discard_ability)) { 2358 return BCM_E_UNAVAIL; 2359 } 2360 2361 if (discard == NULL || 2362 discard->gain < 0 || discard->gain > 15 || 2363 discard->drop_probability < 0 || discard->drop_probability > 100) { 2364 return BCM_E_PARAM; 2365 } 2366 2367 if ((discard->min_thresh < 0) || (discard->max_thresh < 0) || 2368 (discard->min_thresh > discard->max_thresh)) { 2369 return BCM_E_PARAM; 2370 } 2371 2372 cell_size = _BCM_GH_BYTES_PER_CELL; 2373 cell_field_max = GH_CELL_FIELD_MAX; 2374 2375 min_thresh = discard->min_thresh; 2376 max_thresh = discard->max_thresh; 2377 if (discard->flags & BCM_COSQ_DISCARD_BYTES) { 2378 /* Convert bytes to cells */ 2379 min_thresh += (cell_size - 1); 2380 min_thresh /= cell_size; 2381 2382 max_thresh += (cell_size - 1); 2383 max_thresh /= cell_size; 2384 2385 if ((min_thresh > cell_field_max) || 2386 (max_thresh > cell_field_max)) { 2387 return BCM_E_PARAM; 2388 } 2389 } else { /* BCM_COSQ_DISCARD_PACKETS */ 2390 if ((min_thresh > GH_CELL_FIELD_MAX) || 2391 (max_thresh > GH_CELL_FIELD_MAX)) { 2392 return BCM_E_PARAM; 2393 } 2394 } 2395 2396 if (BCM_GPORT_IS_SET(port)) { 2397 BCM_IF_ERROR_RETURN(bcm_esw_port_local_get(unit, port, &local_port)); 2398 BCM_PBMP_PORT_SET(pbmp, local_port); 2399 } else { 2400 if (port == -1) { 2401 BCM_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit)); 2402 } else if (!SOC_PORT_VALID(unit, port) || 2403 (CMIC_PORT(unit) == port)) { 2404 return BCM_E_PORT; 2405 } else { 2406 BCM_PBMP_PORT_SET(pbmp, port); 2407 } 2408 } 2409 2410 if (cosq < -1 || cosq >= _hu_num_cosq[unit]) { 2411 return BCM_E_PARAM; 2412 } 2413 2414 if (cosq == -1) { 2415 numq = _hu_num_cosq[unit]; 2416 cosq = 0; 2417 } else { 2418 numq = 1; 2419 } 2420 2421 BCM_PBMP_ITER(pbmp, local_port) { 2422 for (i = 0; i < numq; i++) { 2423 BCM_IF_ERROR_RETURN 2424 (_bcm_gh_cosq_wred_set(unit, local_port, cosq + i, 2425 discard->flags, 2426 min_thresh, max_thresh, 2427 discard->drop_probability, 2428 discard->gain, 2429 FALSE, 0)); 2430 } 2431 } 2432 2433 return BCM_E_NONE; 2434 } 2435 2436 int 2437 bcm_gh_cosq_gport_discard_get(int unit, bcm_gport_t port, bcm_cos_queue_t cosq, 2438 bcm_cosq_gport_discard_t *discard) 2439 { 2440 uint32 min_thresh, max_thresh; 2441 bcm_port_t local_port; 2442 bcm_pbmp_t pbmp; 2443 2444 if (!soc_feature(unit, soc_feature_discard_ability)) { 2445 return BCM_E_UNAVAIL; 2446 } 2447 2448 if (discard == NULL) { 2449 return BCM_E_PARAM; 2450 } 2451 2452 if (BCM_GPORT_IS_SET(port)) { 2453 BCM_IF_ERROR_RETURN(bcm_esw_port_local_get(unit, port, &local_port)); 2454 } else { 2455 if (port == -1) { 2456 BCM_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit)); 2457 } else if (!SOC_PORT_VALID(unit, port) || 2458 (CMIC_PORT(unit) == port)) { 2459 return BCM_E_PORT; 2460 } else { 2461 /* coverity[overrun-local] */ 2462 BCM_PBMP_PORT_SET(pbmp, port); 2463 } 2464 BCM_PBMP_ITER(pbmp, local_port) { 2465 break; 2466 } 2467 } 2468 2469 if (cosq < -1 || cosq >= _hu_num_cosq[unit]) { 2470 return BCM_E_PARAM; 2471 } 2472 2473 BCM_IF_ERROR_RETURN 2474 (_bcm_gh_cosq_wred_get(unit, local_port, cosq == -1 ? 0 : cosq, 2475 &discard->flags, &min_thresh, &max_thresh, 2476 &discard->drop_probability, &discard->gain, 0)); 2477 2478 if (discard->flags & BCM_COSQ_DISCARD_BYTES) { 2479 /* Convert number of cells to number of bytes */ 2480 min_thresh *= _BCM_GH_BYTES_PER_CELL; 2481 max_thresh *= _BCM_GH_BYTES_PER_CELL; 2482 } 2483 discard->min_thresh = min_thresh; 2484 discard->max_thresh = max_thresh; 2485 2486 return BCM_E_NONE; 2487 } 2488 2489 2490 int 2491 bcm_gh_cosq_discard_port_set(int unit, bcm_port_t port, 2492 bcm_cos_queue_t cosq, 2493 uint32 color, 2494 int drop_start, 2495 int drop_slope, 2496 int average_time) 2497 { 2498 bcm_port_t local_port; 2499 bcm_pbmp_t pbmp; 2500 int gain; 2501 uint32 min_thresh, max_thresh, n; 2502 uint32 rval, bits; 2503 int numq, i, cosq_start; 2504 2505 if (!soc_feature(unit, soc_feature_discard_ability)) { 2506 return BCM_E_UNAVAIL; 2507 } 2508 2509 if (drop_start < 0 || drop_start > 100 || 2510 drop_slope < 0 || drop_slope > 90) { 2511 return BCM_E_PARAM; 2512 } 2513 2514 if (BCM_GPORT_IS_SET(port)) { 2515 BCM_IF_ERROR_RETURN(bcm_esw_port_local_get(unit, port, &local_port)); 2516 BCM_PBMP_PORT_SET(pbmp, local_port); 2517 } else { 2518 if (port == -1) { 2519 BCM_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit)); 2520 } else if (!SOC_PORT_VALID(unit, port) || (CMIC_PORT(unit) == port)) { 2521 return BCM_E_PORT; 2522 } else { 2523 BCM_PBMP_PORT_SET(pbmp, port); 2524 } 2525 } 2526 2527 if (cosq < -1 || cosq >= _hu_num_cosq[unit]) { 2528 return BCM_E_PARAM; 2529 } else if (cosq == -1) { 2530 cosq_start = 0; 2531 numq = _hu_num_cosq[unit]; 2532 } else { 2533 cosq_start = cosq; 2534 numq = 1; 2535 } 2536 2537 /* 2538 * average queue size is reculated every 2us, the formula is 2539 * avg_qsize(t + 1) = 2540 * avg_qsize(t) + (cur_qsize - avg_qsize(t)) / (2 ** gain) 2541 * gain = log2(average_time / 2) 2542 */ 2543 bits = (average_time / _bcm_gh_wred_update_interval[unit]) & 0xffff; 2544 if (bits != 0) { 2545 bits |= bits >> 1; 2546 bits |= bits >> 2; 2547 bits |= bits >> 4; 2548 bits |= bits >> 8; 2549 gain = _shr_popcount(bits) - 1; 2550 } else { 2551 gain = 0; 2552 } 2553 2554 BCM_PBMP_ITER(pbmp, local_port) { 2555 for (i = cosq_start; i < (cosq_start + numq); i++) { 2556 /* Get the start point as a function of the HOL limit */ 2557 SOC_IF_ERROR_RETURN 2558 (READ_HOLCOSPKTSETLIMITr(unit, local_port, i, &rval)); 2559 n = soc_reg_field_get(unit, HOLCOSPKTSETLIMITr, rval, 2560 PKTSETLIMITf); 2561 min_thresh = drop_start * n / 100; 2562 2563 /* Calculate the max threshold. For a given slope (angle in 2564 * degrees), determine how many packets are in the range from 2565 * 0% drop probability to 100% drop probability. Add that 2566 * number to the min_treshold to the the max_threshold. 2567 */ 2568 max_thresh = min_thresh + _bcm_gh_angle_to_cells(drop_slope); 2569 if (max_thresh > GH_CELL_FIELD_MAX) { 2570 max_thresh = GH_CELL_FIELD_MAX; 2571 } 2572 BCM_IF_ERROR_RETURN 2573 (_bcm_gh_cosq_wred_set(unit, local_port, i, 2574 (color | BCM_COSQ_DISCARD_TCP), 2575 min_thresh, max_thresh, 100, 2576 gain, TRUE, 0)); 2577 } 2578 } 2579 2580 return BCM_E_NONE; 2581 } 2582 2583 int 2584 bcm_gh_cosq_discard_port_get(int unit, bcm_port_t port, 2585 bcm_cos_queue_t cosq, 2586 uint32 color, 2587 int *drop_start, 2588 int *drop_slope, 2589 int *average_time) 2590 { 2591 bcm_port_t local_port; 2592 bcm_pbmp_t pbmp; 2593 int gain, drop_prob; 2594 uint32 min_thresh, max_thresh, pkt_limit; 2595 uint32 rval; 2596 2597 if (!soc_feature(unit, soc_feature_discard_ability)) { 2598 return BCM_E_UNAVAIL; 2599 } 2600 2601 if (drop_start == NULL || drop_slope == NULL || average_time == NULL) { 2602 return BCM_E_PARAM; 2603 } 2604 2605 if (BCM_GPORT_IS_SET(port)) { 2606 local_port = port; 2607 } else { 2608 if (port == -1) { 2609 BCM_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit)); 2610 } else if (!SOC_PORT_VALID(unit, port) || (CMIC_PORT(unit) == port)) { 2611 return BCM_E_PORT; 2612 } else { 2613 /* coverity[overrun-local] */ 2614 BCM_PBMP_PORT_SET(pbmp, port); 2615 } 2616 BCM_PBMP_ITER(pbmp, local_port) { 2617 break; 2618 } 2619 } 2620 2621 if (cosq < -1 || cosq >= _hu_num_cosq[unit]) { 2622 return BCM_E_PARAM; 2623 } 2624 2625 color |= BCM_COSQ_DISCARD_TCP; 2626 BCM_IF_ERROR_RETURN 2627 (_bcm_gh_cosq_wred_get(unit, local_port, cosq == -1 ? 0 : cosq, 2628 &color, &min_thresh, &max_thresh, &drop_prob, 2629 &gain, 0)); 2630 2631 /* 2632 * average queue size is reculated every 2(or 1)us, the formula is 2633 * avg_qsize(t + 1) = 2634 * avg_qsize(t) + (cur_qsize - avg_qsize(t)) / (2 ** gain) 2635 */ 2636 *average_time = (1 << gain) * _bcm_gh_wred_update_interval[unit]; 2637 2638 /* Get the total HOL limit first */ 2639 BCM_IF_ERROR_RETURN 2640 (READ_HOLCOSPKTSETLIMITr(unit, local_port, 2641 cosq == -1 ? 0 : cosq, &rval)); 2642 pkt_limit = soc_reg_field_get(unit, HOLCOSPKTSETLIMITr, rval, PKTSETLIMITf); 2643 if (min_thresh > pkt_limit) { 2644 min_thresh = pkt_limit; 2645 } 2646 2647 if (max_thresh > pkt_limit) { 2648 max_thresh = pkt_limit; 2649 } 2650 2651 *drop_start = (min_thresh * 100 + pkt_limit - 1) / pkt_limit; 2652 2653 /* Calculate the slope using the min and max threshold. 2654 * The angle is calculated knowing drop probability at min 2655 * threshold is 0% and drop probability at max threshold is 100%. 2656 */ 2657 *drop_slope = _bcm_gh_cells_to_angle(max_thresh - min_thresh); 2658 return BCM_E_NONE; 2659 } 2660 2661 2662 #endif /* BCM_GREYHOUND_SUPPORT */ 2663 2664 2665 STATIC int 2666 _bcm_hu_cosq_config_set(int unit, int numq) 2667 { 2668 int ncells, nports, xq_per_port, cos; 2669 int n, nreset, used_cells; 2670 int scells, sreset; 2671 soc_port_t port; 2672 uint32 val, limit_red, limit_yel; 2673 soc_mem_t xq_mem; 2674 int mmu_flow_percent; 2675 int mmu_red_drop_percent; 2676 int mmu_yellow_drop_percent; 2677 int mmu_static_bytes; 2678 int mmu_static_cells; 2679 int mmu_static_percent; 2680 int mmu_reset_bytes; 2681 int mmu_reset_cells = 0; 2682 int mmu_overcommit; 2683 int mmu_overcommit_stack; 2684 uint16 dev_id; 2685 uint8 rev_id; 2686 2687 ncells = soc_mem_index_count(unit, MMU_CBPDATA0m); 2688 /* These special variables are for Hawkeye only. 2689 Those values are retrieved from HAWKEYE MMU setting document*/ 2690 2691 nports = NUM_ALL_PORT(unit) + 1; /* Include cmic port as well */ 2692 2693 /* get mmu control config values */ 2694 mmu_flow_percent = soc_property_get(unit, 2695 spn_MMU_FLOW_PERCENT, 2696 MMU_FLOW_PERCENT); 2697 mmu_red_drop_percent = soc_property_get(unit, 2698 spn_MMU_RED_DROP_PERCENT, 2699 MMU_RED_DROP_PERCENT); 2700 mmu_yellow_drop_percent = soc_property_get(unit, 2701 spn_MMU_YELLOW_DROP_PERCENT, 2702 MMU_YELLOW_DROP_PERCENT); 2703 mmu_static_bytes = soc_property_get(unit, 2704 spn_MMU_STATIC_BYTES, 2705 MMU_STATIC_BYTES); 2706 mmu_static_percent = soc_property_get(unit, 2707 spn_MMU_STATIC_PERCENT, 2708 MMU_STATIC_PERCENT); 2709 mmu_reset_bytes = soc_property_get(unit, 2710 spn_MMU_RESET_BYTES, 2711 MMU_RESET_BYTES); 2712 mmu_overcommit = soc_property_get(unit, 2713 spn_MMU_OVERCOMMIT, 2714 MMU_OVERCOMMIT); 2715 mmu_overcommit_stack = soc_property_get(unit, 2716 spn_MMU_OVERCOMMIT_STACK, 2717 MMU_OVERCOMMIT_STACK); 2718 2719 /* sanity check config values */ 2720 if (mmu_flow_percent <= 0 || mmu_flow_percent > 100) { 2721 mmu_flow_percent = 100; 2722 } 2723 if (mmu_red_drop_percent <= 0 || mmu_red_drop_percent > 100) { 2724 mmu_red_drop_percent = 100; 2725 } 2726 if (mmu_yellow_drop_percent <= 0 || mmu_yellow_drop_percent > 100) { 2727 mmu_yellow_drop_percent = 100; 2728 } 2729 if (mmu_static_percent <= 0 || mmu_static_percent > 100) { 2730 mmu_static_percent = MMU_STATIC_PERCENT; 2731 } 2732 if (mmu_overcommit <= 0) { 2733 mmu_overcommit = 1; 2734 } 2735 if (mmu_overcommit_stack <= 0) { 2736 mmu_overcommit_stack = mmu_overcommit; 2737 } 2738 mmu_static_cells = (mmu_static_bytes + MMU_CELL_SIZE - 1) / MMU_CELL_SIZE; 2739 mmu_reset_cells = (mmu_reset_bytes + MMU_CELL_SIZE - 1) / MMU_CELL_SIZE; 2740 2741 /* calculate static limits first */ 2742 if (mmu_static_cells > 0) { 2743 scells = mmu_static_cells; 2744 sreset = scells; /* 100% */ 2745 } else { 2746 scells = (ncells / nports / numq) * mmu_static_percent / 100; 2747 sreset = scells * 75 / 100; /* 75% */ 2748 } 2749 2750 soc_cm_get_id(unit, &dev_id, &rev_id); 2751 if (dev_id == BCM56147_DEVICE_ID) { 2752 scells += 4; 2753 sreset = scells; 2754 } 2755 2756 used_cells = scells * numq * nports; 2757 2758 /* remaining cells are dynamic */ 2759 n = ncells - used_cells; 2760 if (n <= 0) { 2761 n = 0; 2762 } 2763 nreset = n - mmu_reset_cells; 2764 if (nreset < (n * MMU_RESET_MIN_PERCENT / 100)) { 2765 nreset = n * MMU_RESET_MIN_PERCENT / 100; 2766 } 2767 if (nreset <= 0) { 2768 nreset = 1; 2769 } 2770 2771 /* device wide dynamic limits */ 2772 2773 SOC_IF_ERROR_RETURN(READ_TOTALDYNCELLSETLIMITr(unit, &val)); 2774 soc_reg_field_set(unit, TOTALDYNCELLSETLIMITr, 2775 &val, TOTALDYNCELLSETLIMITf, n); 2776 SOC_IF_ERROR_RETURN(WRITE_TOTALDYNCELLSETLIMITr(unit, val)); 2777 SOC_IF_ERROR_RETURN(READ_TOTALDYNCELLRESETLIMITr(unit, &val)); 2778 soc_reg_field_set(unit, TOTALDYNCELLRESETLIMITr, 2779 &val, TOTALDYNCELLRESETLIMITf, nreset); 2780 SOC_IF_ERROR_RETURN(WRITE_TOTALDYNCELLRESETLIMITr(unit, val)); 2781 2782 /* per-port dynamic limits */ 2783 PBMP_ALL_ITER(unit, port) { 2784 2785 if (dev_id == BCM56147_DEVICE_ID) { 2786 /* For Hurricane(56147 variant), the value of field DYNCELLLIMIT 2787 * of register DYNCELLLIMIT is 8448 and DYNCELLRESETLIMIT is 8424, 2788 * refer hurricane_mmu_init for detailed computation */ 2789 2790 SOC_IF_ERROR_RETURN(READ_DYNCELLLIMITr(unit, port, &val)); 2791 if (soc_reg_field_valid(unit, DYNCELLLIMITr, DYNCELLLIMITf)) { 2792 soc_reg_field_set(unit, DYNCELLLIMITr, &val, 2793 DYNCELLLIMITf, 8448); 2794 } 2795 2796 if (soc_reg_field_valid(unit, DYNCELLLIMITr, DYNCELLRESETLIMITf)) { 2797 soc_reg_field_set(unit, DYNCELLLIMITr, &val, 2798 DYNCELLRESETLIMITf, 8424); 2799 } 2800 } 2801 else { 2802 /* For other variants use 6040 and 6016 */ 2803 SOC_IF_ERROR_RETURN(READ_DYNCELLLIMITr(unit, port, &val)); 2804 if (soc_reg_field_valid(unit, DYNCELLLIMITr, DYNCELLLIMITf)) { 2805 soc_reg_field_set(unit, DYNCELLLIMITr, &val, 2806 DYNCELLLIMITf, 6040); 2807 } 2808 2809 if (soc_reg_field_valid(unit, DYNCELLLIMITr, DYNCELLRESETLIMITf)) { 2810 soc_reg_field_set(unit, DYNCELLLIMITr, &val, 2811 DYNCELLRESETLIMITf, 6016); 2812 } 2813 } 2814 2815 2816 SOC_IF_ERROR_RETURN(WRITE_DYNCELLLIMITr(unit, port, val)); 2817 2818 2819 /* 2820 * Number of transactions allocated to each port, 2821 * shared between that port's active cosqs. 2822 */ 2823 SOC_IF_ERROR_RETURN(soc_hu_xq_mem(unit, port, &xq_mem)); 2824 xq_per_port = soc_mem_index_count(unit, xq_mem); 2825 2826 2827 /* 2828 * Divide weighted per-port packet limits into each cos. 2829 * Initialize all COSQs, even the inactive ones. 2830 */ 2831 for (cos = 0; cos < NUM_COS(unit); cos++) { 2832 /* set per-port static limits (calculated earlier) */ 2833 SOC_IF_ERROR_RETURN 2834 (READ_LWMCOSCELLSETLIMITr(unit, port, cos, &val)); 2835 if (soc_reg_field_valid(unit, LWMCOSCELLSETLIMITr, 2836 CELLSETLIMITf)) { 2837 soc_reg_field_set(unit, LWMCOSCELLSETLIMITr, 2838 &val, CELLSETLIMITf, 2839 cos < numq ? scells : 0); 2840 } 2841 2842 if (soc_reg_field_valid(unit, LWMCOSCELLSETLIMITr, 2843 CELLRESETLIMITf)) { 2844 soc_reg_field_set(unit, LWMCOSCELLSETLIMITr, 2845 &val, CELLRESETLIMITf, 2846 cos < numq ? sreset : 0); 2847 } 2848 SOC_IF_ERROR_RETURN 2849 (WRITE_LWMCOSCELLSETLIMITr(unit, port, cos, val)); 2850 2851 2852 /* set red and yellow drop limits */ 2853 /* set as a percentage of the green drop (HOL) limit */ 2854 2855 SOC_IF_ERROR_RETURN 2856 (READ_HOLCOSPKTSETLIMITr(unit, port, cos, &val)); 2857 n = soc_reg_field_get(unit, HOLCOSPKTSETLIMITr, val, 2858 PKTSETLIMITf); 2859 2860 /* Make sure numq will work with the cosq weighting. */ 2861 if ((cos < numq) && (n == 4)) { 2862 /* 2863 * This means that this COSQ has been 2864 * disabled due to XQ weighting, but 2865 * has been selected as active. Config error. 2866 */ 2867 return BCM_E_PARAM; 2868 } 2869 2870 /* per-queue packet red and yellow drop */ 2871 if (cos < numq) { 2872 limit_red = n * mmu_red_drop_percent / 100; 2873 limit_yel = n * mmu_yellow_drop_percent / 100; 2874 } else { 2875 limit_red = xq_per_port - 1; /* Max limit (disabled) */ 2876 limit_yel = xq_per_port - 1; /* Max limit (disabled) */ 2877 } 2878 2879 /* Granularity limitation */ 2880 limit_red /= BCM_HU_CNG_PKT_LIMIT_GRANULARITY; 2881 limit_yel /= BCM_HU_CNG_PKT_LIMIT_GRANULARITY; 2882 2883 2884 val = 0; 2885 soc_reg_field_set(unit, CNGCOSPKTLIMIT0r, &val, 2886 CNGPKTSETLIMIT0f, limit_red); 2887 SOC_IF_ERROR_RETURN(WRITE_CNGCOSPKTLIMIT0r(unit, port, cos, val)); 2888 2889 val = 0; 2890 soc_reg_field_set(unit, CNGCOSPKTLIMIT1r, &val, 2891 CNGPKTSETLIMIT1f, limit_yel); 2892 SOC_IF_ERROR_RETURN(WRITE_CNGCOSPKTLIMIT1r(unit, port, cos, val)); 2893 2894 2895 } 2896 2897 2898 if (dev_id == BCM56147_DEVICE_ID) { 2899 SOC_IF_ERROR_RETURN(READ_IBPCELLSETLIMITr(unit, port, &val)); 2900 2901 /* set cell limit = 36 as recommended by design team */ 2902 soc_reg_field_set(unit, IBPCELLSETLIMITr, &val, 2903 CELLSETLIMITf, 36); 2904 SOC_IF_ERROR_RETURN(WRITE_IBPCELLSETLIMITr(unit, port, val)); 2905 2906 SOC_IF_ERROR_RETURN(READ_IBPPKTSETLIMITr(unit, port, &val)); 2907 /* set pkt set limit = 33 as recommended by design team */ 2908 soc_reg_field_set(unit, IBPPKTSETLIMITr, &val, 2909 PKTSETLIMITf, 33); 2910 soc_reg_field_set(unit, IBPPKTSETLIMITr, &val, 2911 RESETLIMITSELf, 0); 2912 SOC_IF_ERROR_RETURN(WRITE_IBPPKTSETLIMITr(unit, port, val)); 2913 } 2914 else { 2915 SOC_IF_ERROR_RETURN(READ_IBPCELLSETLIMITr(unit, port, &val)); 2916 2917 /* set cell limit = 80 (9728/128 +4); 9728 is max pkt size and 128 is cell size ; 2918 * as recommended by design team */ 2919 soc_reg_field_set(unit, IBPCELLSETLIMITr, &val, 2920 CELLSETLIMITf, 80); 2921 SOC_IF_ERROR_RETURN(WRITE_IBPCELLSETLIMITr(unit, port, val)); 2922 2923 SOC_IF_ERROR_RETURN(READ_IBPPKTSETLIMITr(unit, port, &val)); 2924 /* set pkt set limit = 12 as recommended by design team */ 2925 soc_reg_field_set(unit, IBPPKTSETLIMITr, &val, 2926 PKTSETLIMITf, 12); 2927 soc_reg_field_set(unit, IBPPKTSETLIMITr, &val, 2928 RESETLIMITSELf, 0); 2929 SOC_IF_ERROR_RETURN(WRITE_IBPPKTSETLIMITr(unit, port, val)); 2930 } 2931 2932 SOC_IF_ERROR_RETURN(READ_IBPDISCARDSETLIMITr(unit, port, &val)); 2933 soc_reg_field_set(unit, IBPDISCARDSETLIMITr, &val, 2934 DISCARDSETLIMITf, ncells-1); 2935 SOC_IF_ERROR_RETURN(WRITE_IBPDISCARDSETLIMITr(unit, port, val)); 2936 2937 } 2938 2939 /* Overall MMU controls */ 2940 SOC_IF_ERROR_RETURN(READ_MISCCONFIGr(unit, &val)); 2941 soc_reg_field_set(unit, MISCCONFIGr, &val, DYNAMIC_MEMORY_ENf, 1); 2942 2943 /* set skidmarker to 3 */ 2944 soc_reg_field_set(unit, MISCCONFIGr, &val, SKIDMARKERf, 3); 2945 2946 2947 if (soc_reg_field_valid(unit, MISCCONFIGr, HOL_CELL_SOP_DROP_ENf)) { 2948 soc_reg_field_set(unit, MISCCONFIGr, &val, HOL_CELL_SOP_DROP_ENf, 1); 2949 } 2950 2951 2952 SOC_IF_ERROR_RETURN(WRITE_MISCCONFIGr(unit, val)); 2953 2954 return BCM_E_NONE; 2955 } 2956 2957 /* 2958 * Function: 2959 * bcm_cosq_mapping_set 2960 * Purpose: 2961 * Set which cosq a given priority should fall into 2962 * Parameters: 2963 * unit - StrataSwitch unit number. 2964 * priority - Priority value to map 2965 * cosq - COS queue to map to 2966 * Returns: 2967 * BCM_E_XXX 2968 */ 2969 2970 int 2971 bcm_hu_cosq_mapping_set(int unit, bcm_port_t port, 2972 bcm_cos_t priority, bcm_cos_queue_t cosq) 2973 { 2974 uint32 val, old_index, new_index; 2975 int i; 2976 port_cos_map_entry_t cos_map_array[HU_COS_MAP_ENTRIES_PER_SET], *entry_p; 2977 void *entries[HU_COS_MAP_ENTRIES_PER_SET]; 2978 bcm_pbmp_t ports; 2979 bcm_port_t local_port; 2980 2981 if (priority < 0 || priority >= 16) { 2982 return (BCM_E_PARAM); 2983 } 2984 2985 if (cosq < 0 || cosq >= _hu_num_cosq[unit]) { 2986 return (BCM_E_PARAM); 2987 } 2988 2989 if (port == -1) { /* all ports */ 2990 BCM_PBMP_ASSIGN(ports, PBMP_ALL(unit)); 2991 } else { 2992 if (BCM_GPORT_IS_SET(port)) { 2993 BCM_IF_ERROR_RETURN( 2994 bcm_esw_port_local_get(unit, port, &local_port)); 2995 } else { 2996 local_port = port; 2997 } 2998 2999 if (!SOC_PORT_VALID(unit, local_port) || !IS_ALL_PORT(unit, local_port)) { 3000 return BCM_E_PORT; 3001 } 3002 BCM_PBMP_CLEAR(ports); 3003 BCM_PBMP_PORT_ADD(ports, local_port); 3004 } 3005 3006 PBMP_ITER(ports, local_port) { 3007 SOC_IF_ERROR_RETURN(READ_COS_MAP_SELr(unit, local_port, &val)); 3008 old_index = soc_reg_field_get(unit, COS_MAP_SELr, val, SELECTf); 3009 old_index *= HU_COS_MAP_ENTRIES_PER_SET; 3010 3011 /* get current mapping profile values */ 3012 for (i = 0; i < HU_COS_MAP_ENTRIES_PER_SET; i++) { 3013 entry_p = SOC_PROFILE_MEM_ENTRY(unit, _hu_cos_map_profile[unit], 3014 port_cos_map_entry_t *, (old_index + i)); 3015 memcpy(&cos_map_array[i], entry_p, sizeof(*entry_p)); 3016 entries[i] = (void *) &cos_map_array[i]; 3017 } 3018 soc_mem_field32_set(unit, PORT_COS_MAPm, 3019 &cos_map_array[priority], COSf, cosq); 3020 SOC_IF_ERROR_RETURN 3021 (soc_profile_mem_add(unit, _hu_cos_map_profile[unit], 3022 (void *) &entries, 3023 HU_COS_MAP_ENTRIES_PER_SET, &new_index)); 3024 SOC_IF_ERROR_RETURN 3025 (soc_reg_field32_modify(unit, COS_MAP_SELr, local_port, 3026 SELECTf, 3027 new_index / HU_COS_MAP_ENTRIES_PER_SET)); 3028 SOC_IF_ERROR_RETURN 3029 (soc_profile_mem_delete(unit, _hu_cos_map_profile[unit], old_index)); 3030 3031 #ifndef BCM_COSQ_HIGIG_MAP_DISABLE 3032 if (IS_HG_PORT(unit, local_port) || local_port == CMIC_PORT(unit)) { 3033 SOC_IF_ERROR_RETURN 3034 (soc_profile_mem_add(unit, _hu_cos_map_profile[unit], 3035 (void *) &entries, 3036 HU_COS_MAP_ENTRIES_PER_SET, &new_index)); 3037 SOC_IF_ERROR_RETURN 3038 (soc_reg_field32_modify(unit, ICOS_MAP_SELr, local_port, 3039 SELECTf, 3040 new_index / HU_COS_MAP_ENTRIES_PER_SET)); 3041 SOC_IF_ERROR_RETURN 3042 (soc_profile_mem_delete(unit, _hu_cos_map_profile[unit], old_index)); 3043 } 3044 #endif 3045 } 3046 return BCM_E_NONE; 3047 } 3048 3049 /* 3050 * Function: 3051 * bcm_cosq_mapping_get 3052 * Purpose: 3053 * Determine which COS queue a given priority currently maps to. 3054 * Parameters: 3055 * unit - StrataSwitch unit number. 3056 * priority - Priority value 3057 * cosq - (Output) COS queue number 3058 * Returns: 3059 * BCM_E_XXX 3060 */ 3061 3062 int 3063 bcm_hu_cosq_mapping_get(int unit, bcm_port_t port, 3064 bcm_cos_t priority, bcm_cos_queue_t *cosq) 3065 { 3066 uint32 val; 3067 int index; 3068 port_cos_map_entry_t *entry_p; 3069 bcm_port_t local_port; 3070 3071 if (priority < 0 || priority >= 16) { 3072 return (BCM_E_PARAM); 3073 } 3074 3075 if (port == -1) { 3076 local_port = REG_PORT_ANY; 3077 } else { 3078 if (BCM_GPORT_IS_SET(port)) { 3079 BCM_IF_ERROR_RETURN( 3080 bcm_esw_port_local_get(unit, port, &local_port)); 3081 } else { 3082 local_port = port; 3083 } 3084 3085 if (!SOC_PORT_VALID(unit, local_port) || !IS_ALL_PORT(unit, local_port)) { 3086 return BCM_E_PORT; 3087 } 3088 } 3089 3090 SOC_IF_ERROR_RETURN(READ_COS_MAP_SELr(unit, local_port, &val)); 3091 index = soc_reg_field_get(unit, COS_MAP_SELr, val, SELECTf); 3092 index *= HU_COS_MAP_ENTRIES_PER_SET; 3093 3094 entry_p = SOC_PROFILE_MEM_ENTRY(unit, _hu_cos_map_profile[unit], 3095 port_cos_map_entry_t *, 3096 (index + priority)); 3097 *cosq = soc_mem_field32_get(unit, PORT_COS_MAPm, entry_p, COSf); 3098 return BCM_E_NONE; 3099 } 3100 3101 STATIC int 3102 _bcm_hu_cosq_gport_bandwidth_port_resolve(int unit, bcm_gport_t gport, 3103 bcm_cos_queue_t cosq, 3104 bcm_port_t *local_port, 3105 bcm_cos_queue_t *cosq_start, 3106 bcm_cos_queue_t *cosq_end) 3107 { 3108 bcm_module_t modid; 3109 bcm_trunk_t trunk_id; 3110 int is_local; 3111 3112 if (BCM_GPORT_IS_SET(gport)) { 3113 BCM_IF_ERROR_RETURN 3114 (_bcm_hu_cosq_resolve_mod_port(unit, gport, &modid, 3115 local_port, &trunk_id, &is_local)); 3116 } else { 3117 *local_port = gport; 3118 if (!SOC_PORT_VALID(unit, gport)) { 3119 return BCM_E_PORT; 3120 } 3121 } 3122 3123 if (cosq < -1) { 3124 return BCM_E_PARAM; 3125 } 3126 3127 /* hurricane does not have vlan queues and S1 scheduler*/ 3128 if (cosq >= _hu_num_cosq[unit]) { 3129 return BCM_E_PARAM; 3130 } else if (cosq < 0) { 3131 *cosq_start = 0; 3132 *cosq_end = _hu_num_cosq[unit] - 1; 3133 } else { 3134 *cosq_start = *cosq_end = cosq; 3135 } 3136 3137 return BCM_E_NONE; 3138 } 3139 3140 3141 /* 3142 * Function: 3143 * bcm_hu_cosq_gport_bandwidth_burst_get 3144 * Purpose: 3145 * 3146 * Parameters: 3147 * unit - (IN) Unit number. 3148 * gport - (IN) GPORT ID. 3149 * cosq - (IN) COS queue to configure, -1 for all COS queues. 3150 * kbits_burst - (OUT) maximum burst, kbits. 3151 * Returns: 3152 * BCM_E_XXX 3153 */ 3154 int 3155 bcm_hu_cosq_gport_bandwidth_burst_get(int unit, bcm_gport_t gport, 3156 bcm_cos_queue_t cosq, 3157 uint32 *kbits_burst) 3158 { 3159 bcm_port_t local_port, port; 3160 bcm_cos_queue_t cosq_start = 0, cosq_end = 0; 3161 uint32 kbits_sec_min, kbits_sec_max, flags; /* Dummy variables */ 3162 3163 if (gport < 0) { 3164 port = SOC_PORT_MIN(unit,all); 3165 3166 BCM_IF_ERROR_RETURN 3167 (_bcm_hu_cosq_gport_bandwidth_port_resolve(unit, port, cosq, 3168 &local_port, 3169 &cosq_start, &cosq_end)); 3170 } else { 3171 BCM_IF_ERROR_RETURN 3172 (_bcm_hu_cosq_gport_bandwidth_port_resolve(unit, gport, cosq, 3173 &local_port, 3174 &cosq_start, &cosq_end)); 3175 } 3176 3177 kbits_sec_min = kbits_sec_max = flags = 0; 3178 3179 BCM_IF_ERROR_RETURN 3180 (bcm_hu_cosq_port_bandwidth_get(unit, local_port, cosq_start, 3181 &kbits_sec_min, &kbits_sec_max, 3182 kbits_burst, &flags)); 3183 return BCM_E_NONE; 3184 } 3185 3186 /* 3187 * Function: 3188 * bcm_hu_cosq_gport_bandwidth_burst_set 3189 * Purpose: 3190 * 3191 * Parameters: 3192 * unit - (IN) Unit number. 3193 * gport - (IN) GPORT ID. 3194 * cosq - (IN) COS queue to configure, -1 for all COS queues. 3195 * kbits_burst - (IN) maximum burst, kbits. 3196 * Returns: 3197 * BCM_E_XXX 3198 */ 3199 int 3200 bcm_hu_cosq_gport_bandwidth_burst_set(int unit, bcm_gport_t gport, 3201 bcm_cos_queue_t cosq, 3202 uint32 kbits_burst) 3203 { 3204 bcm_port_t local_port, port; 3205 int i; 3206 bcm_cos_queue_t cosq_start = 0, cosq_end = 0; 3207 uint32 kbits_sec_min, kbits_sec_max, flags; 3208 uint32 kbits_sec_burst; /* Dummy variable */ 3209 3210 if (gport < 0) { 3211 PBMP_ALL_ITER(unit, port) { 3212 BCM_IF_ERROR_RETURN 3213 (_bcm_hu_cosq_gport_bandwidth_port_resolve(unit, port, cosq, 3214 &local_port, 3215 &cosq_start, &cosq_end)); 3216 for (i = cosq_start; i <= cosq_end; i++) { 3217 BCM_IF_ERROR_RETURN 3218 (bcm_hu_cosq_port_bandwidth_get(unit, local_port, i, 3219 &kbits_sec_min, &kbits_sec_max, 3220 &kbits_sec_burst, &flags)); 3221 BCM_IF_ERROR_RETURN 3222 (bcm_hu_cosq_port_bandwidth_set(unit, local_port, i, 3223 kbits_sec_min, 3224 kbits_sec_max, 3225 kbits_burst, 3226 flags)); 3227 } 3228 } 3229 return BCM_E_NONE; 3230 } 3231 3232 BCM_IF_ERROR_RETURN 3233 (_bcm_hu_cosq_gport_bandwidth_port_resolve(unit, gport, cosq, 3234 &local_port, 3235 &cosq_start, &cosq_end)); 3236 3237 for (i = cosq_start; i <= cosq_end; i++) { 3238 BCM_IF_ERROR_RETURN 3239 (bcm_hu_cosq_port_bandwidth_get(unit, local_port, cosq_start, 3240 &kbits_sec_min, &kbits_sec_max, 3241 &kbits_sec_burst, &flags)); 3242 BCM_IF_ERROR_RETURN 3243 (bcm_hu_cosq_port_bandwidth_set(unit, local_port, i, 3244 kbits_sec_min, 3245 kbits_sec_max, 3246 kbits_burst, 3247 flags)); 3248 } 3249 return BCM_E_NONE; 3250 } 3251 3252 /* 3253 * Function: 3254 * bcm_hu_cosq_sched_weight_max_get 3255 * Purpose: 3256 * Retrieve maximum weights for given COS policy. 3257 * Parameters: 3258 * unit - StrataSwitch unit number. 3259 * mode - Scheduling mode, one of BCM_COSQ_xxx 3260 * weight_max - (output) Maximum weight for COS queue. 3261 * For DRR mode Weight is specified in Kbytes 3262 * 0 if mode is BCM_COSQ_STRICT. 3263 * 1 if mode is BCM_COSQ_ROUND_ROBIN. 3264 * -1 if not applicable to mode. 3265 * Returns: 3266 * BCM_E_XXX 3267 */ 3268 3269 int 3270 bcm_hu_cosq_sched_weight_max_get(int unit, int mode, int *weight_max) 3271 { 3272 switch (mode) { 3273 case BCM_COSQ_STRICT: 3274 *weight_max = BCM_COSQ_WEIGHT_STRICT; 3275 break; 3276 case BCM_COSQ_ROUND_ROBIN: 3277 *weight_max = BCM_COSQ_WEIGHT_MIN; 3278 break; 3279 case BCM_COSQ_WEIGHTED_ROUND_ROBIN: 3280 *weight_max = HU_WRR_WEIGHT_MAX; 3281 break; 3282 case BCM_COSQ_DEFICIT_ROUND_ROBIN: 3283 /*max weight in kb will be 3284 max weight * max value of MTU quanta sel */ 3285 *weight_max = HU_DRR_WEIGHT_MAX * MTU_HU_Quanta[BCM_HU_MTU_QUANTA_ID_COUNT-1]; 3286 break; 3287 default: 3288 *weight_max = BCM_COSQ_WEIGHT_UNLIMITED; 3289 return BCM_E_PARAM; 3290 } 3291 3292 return BCM_E_NONE; 3293 } 3294 3295 #ifndef BCM_SW_STATE_DUMP_DISABLE 3296 /* 3297 * Function: 3298 * bcm_hu_cosq_sw_dump 3299 * Purpose: 3300 * Displays COS Queue information maintained by software. 3301 * Parameters: 3302 * unit - Device unit number 3303 * Returns: 3304 * None 3305 */ 3306 void 3307 bcm_hu_cosq_sw_dump(int unit) 3308 { 3309 int i; 3310 3311 LOG_CLI((BSL_META_U(unit, 3312 "\nSW Information COSQ - Unit %d\n"), unit)); 3313 3314 /* Number COSQ */ 3315 LOG_CLI((BSL_META_U(unit, 3316 " Number: %d\n"), _hu_num_cosq[unit])); 3317 3318 /* COSQ Map profile */ 3319 /* Display those entries with reference count > 0 */ 3320 LOG_CLI((BSL_META_U(unit, 3321 " COSQ Map Profile:\n"))); 3322 if (_hu_cos_map_profile[unit] != NULL) { 3323 int num_entries; 3324 int ref_count; 3325 int entries_per_set; 3326 uint32 index; 3327 port_cos_map_entry_t *entry_p; 3328 uint32 cosq, hg_cosq; 3329 3330 num_entries = soc_mem_index_count 3331 (unit, _hu_cos_map_profile[unit]->tables[0].mem); 3332 LOG_CLI((BSL_META_U(unit, 3333 " Number of entries: %d\n"), num_entries)); 3334 LOG_CLI((BSL_META_U(unit, 3335 " Index RefCount EntriesPerSet - " 3336 "COS HG_COS\n"))); 3337 3338 for (index = 0; index < num_entries; 3339 index += HU_COS_MAP_ENTRIES_PER_SET) { 3340 if (SOC_FAILURE 3341 (soc_profile_mem_ref_count_get(unit, 3342 _hu_cos_map_profile[unit], 3343 index, &ref_count))) { 3344 break; 3345 } 3346 3347 if (ref_count <= 0) { 3348 continue; 3349 } 3350 3351 for (i = 0; i < HU_COS_MAP_ENTRIES_PER_SET; i++) { 3352 entries_per_set = 3353 _hu_cos_map_profile[unit]->tables[0].entries[index+i].entries_per_set; 3354 LOG_CLI((BSL_META_U(unit, 3355 " %5d %8d %13d "), 3356 index + i, ref_count, entries_per_set)); 3357 3358 entry_p = SOC_PROFILE_MEM_ENTRY(unit, 3359 _hu_cos_map_profile[unit], 3360 port_cos_map_entry_t *, 3361 index + i); 3362 cosq = soc_mem_field32_get(unit, 3363 PORT_COS_MAPm, 3364 entry_p, 3365 COSf); 3366 LOG_CLI((BSL_META_U(unit, 3367 "%2d "), cosq)); 3368 if (soc_mem_field_valid(unit, PORT_COS_MAPm, HG_COSf)) { 3369 hg_cosq = soc_mem_field32_get(unit, PORT_COS_MAPm, 3370 entry_p, 3371 HG_COSf); 3372 LOG_CLI((BSL_META_U(unit, 3373 " %2d"), hg_cosq)); 3374 } 3375 LOG_CLI((BSL_META_U(unit, 3376 "\n"))); 3377 } 3378 } 3379 } 3380 3381 return; 3382 } 3383 #endif /* BCM_SW_STATE_DUMP_DISABLE */ 3384 3385 #if defined(BCM_GREYHOUND_SUPPORT) 3386 int 3387 _bcm_gh_cosq_pfc_class_resolve(bcm_switch_control_t sctype, int *class) 3388 { 3389 switch (sctype) { 3390 case bcmSwitchPFCClass7Queue: 3391 *class = 7; 3392 break; 3393 case bcmSwitchPFCClass6Queue: 3394 *class = 6; 3395 break; 3396 case bcmSwitchPFCClass5Queue: 3397 *class = 5; 3398 break; 3399 case bcmSwitchPFCClass4Queue: 3400 *class = 4; 3401 break; 3402 case bcmSwitchPFCClass3Queue: 3403 *class = 3; 3404 break; 3405 case bcmSwitchPFCClass2Queue: 3406 *class = 2; 3407 break; 3408 case bcmSwitchPFCClass1Queue: 3409 *class = 1; 3410 break; 3411 case bcmSwitchPFCClass0Queue: 3412 *class = 0; 3413 break; 3414 default: 3415 return BCM_E_UNAVAIL; 3416 } 3417 3418 return BCM_E_NONE; 3419 } 3420 3421 int 3422 bcm_gh_cosq_port_pfc_op(int unit, bcm_port_t port, 3423 bcm_switch_control_t sctype, _bcm_cosq_op_t op, 3424 bcm_cos_queue_t cosq) 3425 { 3426 int class; 3427 uint32 class_bmp; 3428 int i; 3429 3430 BCM_IF_ERROR_RETURN(_bcm_gh_cosq_pfc_class_resolve(sctype, &class)); 3431 3432 if (op == _BCM_COSQ_OP_CLEAR) { 3433 for (i = 0; i < 8; i++) { 3434 BCM_IF_ERROR_RETURN(READ_PRI2COS_PFCr(unit, port, 3435 i, &class_bmp)); 3436 class_bmp &= ~(1 << class); 3437 BCM_IF_ERROR_RETURN(WRITE_PRI2COS_PFCr(unit, port, 3438 i, class_bmp)); 3439 } 3440 } else if (op == _BCM_COSQ_OP_ADD) { 3441 if ((cosq < 0) || cosq > NUM_COS(unit)) { 3442 return BCM_E_PARAM; 3443 } 3444 3445 BCM_IF_ERROR_RETURN(READ_PRI2COS_PFCr(unit, port, cosq, &class_bmp)); 3446 class_bmp |= (1 << class); 3447 BCM_IF_ERROR_RETURN(WRITE_PRI2COS_PFCr(unit, port, cosq, class_bmp)); 3448 } else { 3449 return BCM_E_PARAM; 3450 } 3451 3452 return BCM_E_NONE; 3453 } 3454 3455 int 3456 bcm_gh_cosq_port_pfc_get(int unit, bcm_port_t port, 3457 bcm_switch_control_t sctype, 3458 bcm_cos_queue_t *cosq) 3459 { 3460 int class; 3461 uint32 class_bmp; 3462 int i; 3463 3464 BCM_IF_ERROR_RETURN(_bcm_gh_cosq_pfc_class_resolve(sctype, &class)); 3465 3466 for (i = 0; i < 8; i++) { 3467 BCM_IF_ERROR_RETURN(READ_PRI2COS_PFCr(unit, port, i, &class_bmp)); 3468 if (class_bmp & (1 << class)) { 3469 break; 3470 } 3471 } 3472 3473 if (i >= 8) { 3474 return BCM_E_NOT_FOUND; 3475 } 3476 3477 *cosq = i; 3478 3479 return BCM_E_NONE; 3480 } 3481 #endif /* BCM_GREYHOUND_SUPPORT */ 3482 3483 int 3484 bcm_hr3_cosq_drop_status_enable_set(int unit, bcm_port_t port, int enable) 3485 { 3486 uint32 rval; 3487 bcm_port_t local_port; 3488 3489 COMPILER_REFERENCE(port); 3490 PBMP_E_ITER (unit, local_port) { 3491 BCM_IF_ERROR_RETURN(READ_E2ECC_PORT_CONFIGr(unit, local_port, &rval)); 3492 soc_reg_field_set(unit, E2ECC_PORT_CONFIGr, &rval, 3493 COS_CELL_ENf, enable ? 0xFF : 0x0); 3494 soc_reg_field_set(unit, E2ECC_PORT_CONFIGr, &rval, 3495 COS_PKT_ENf, enable ? 0xFF : 0x0); 3496 BCM_IF_ERROR_RETURN(WRITE_E2ECC_PORT_CONFIGr(unit, local_port, rval)); 3497 } 3498 3499 BCM_IF_ERROR_RETURN(READ_E2ECC_MODEr(unit, &rval)); 3500 soc_reg_field_set(unit, E2ECC_MODEr, &rval, ENf, 3501 enable ? 1 : 0); 3502 BCM_IF_ERROR_RETURN(WRITE_E2ECC_MODEr(unit, rval)); 3503 3504 PBMP_E_ITER (unit, local_port) { 3505 BCM_IF_ERROR_RETURN(READ_COLOR_DROP_ENr(unit, local_port, &rval)); 3506 soc_reg_field_set(unit, COLOR_DROP_ENr, &rval, 3507 COLOR_DROP_ENf, enable ? 0x0 : 0xff); 3508 BCM_IF_ERROR_RETURN(WRITE_COLOR_DROP_ENr(unit, local_port, rval)); 3509 } 3510 3511 return BCM_E_NONE; 3512 } 3513 3514 #else /* BCM_HURRICANE_SUPPORT */ 3515 int _hu_cosq_not_empty; 3516 #endif /* BCM_HURRICANE_SUPPORT */ 3517 3518