cosq.c (155999B)
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 <sal/core/libc.h> 12 #include <shared/bsl.h> 13 #include <soc/defs.h> 14 #if defined(BCM_TRX_SUPPORT) 15 #include <soc/drv.h> 16 #include <soc/scache.h> 17 #include <soc/profile_mem.h> 18 19 #include <bcm/error.h> 20 #include <bcm/cosq.h> 21 22 #include <bcm_int/esw/cosq.h> 23 #include <bcm_int/esw/mbcm.h> 24 #include <bcm_int/esw/firebolt.h> 25 #include <bcm_int/esw/stack.h> 26 #ifdef BCM_SCORPION_SUPPORT 27 #include <bcm_int/esw/scorpion.h> 28 #endif 29 #include <bcm_int/esw/triumph.h> 30 31 #include <bcm_int/esw_dispatch.h> 32 33 #ifdef BCM_WARM_BOOT_SUPPORT 34 #include <bcm_int/esw/switch.h> 35 #endif /* BCM_WARM_BOOT_SUPPORT */ 36 37 #define TR_DRR_WEIGHT_MAX 0x7f 38 #define TR_WRR_WEIGHT_MAX 0x7f 39 40 #define TR_PACKET_FIELD_MAX(_u_) (SOC_IS_ENDURO(_u_) ? (0x1fff) : (0x3fff)) 41 #define TR_CELL_FIELD_MAX(_u_) (SOC_IS_ENDURO(_u_) ? (0x3fff) : (0x7fff)) 42 43 #define TR_PKT_REFRESH_MAX(_u_) (SOC_IS_ENDURO(_u_) ? (0x3ffff) : (0xfffff)) 44 #define TR_PKT_THD_MAX(_u_) (SOC_IS_ENDURO(_u_) ? (0xfff) : (0x7ff)) 45 46 /* COSQ where output of hierarchical COSQs scheduler is attached */ 47 #define TR_SCHEDULER_COSQ 8 48 49 /* MMU cell size in bytes */ 50 #define _BCM_TR_COSQ_CELLSIZE 128 51 52 #ifdef BCM_SCORPION_SUPPORT 53 #define SC_CELL_FIELD_MAX 0x3fff 54 #define _BCM_SC_COSQ_CELLSIZE 128 55 STATIC int _bcm_sc_cosq_discard_all_disable (int unit); 56 #endif 57 58 59 /* Cache of COS_MAP Profile Table */ 60 #define TR_COS_MAP_ENTRIES_PER_SET 16 /* COS Map profile entries per set */ 61 STATIC soc_profile_mem_t *_tr_cos_map_profile[BCM_MAX_NUM_UNITS] = {NULL}; 62 63 /* Number of COSQs configured for this device */ 64 STATIC int _tr_num_cosq[SOC_MAX_NUM_DEVICES]; 65 66 /* Port Bitmap which includes ports capable of hierarchical queueing */ 67 STATIC soc_pbmp_t _tr_cosq_24q_ports[SOC_MAX_NUM_DEVICES]; 68 69 /* Array to keep track of the number of hierarchical COSQs added per port */ 70 STATIC uint8 *_tr_num_port_cosq[SOC_MAX_NUM_DEVICES] = {NULL}; 71 72 /* Forward declarations */ 73 STATIC int _bcm_tr_cosq_gport_delete(int unit, bcm_port_t port); 74 STATIC int _bcm_tr_cosq_port_sched_set(int unit, soc_reg_t config_reg, 75 soc_reg_t weight_reg, soc_reg_t minsp_reg, 76 bcm_port_t port, bcm_cos_queue_t start_cosq, 77 int num_weights, const int weights[], 78 int mode); 79 STATIC int _bcm_tr_cosq_discard_set(int unit, bcm_port_t port, uint32 flags, 80 bcm_cos_queue_t cosq, soc_reg_t config_reg, 81 soc_reg_t thresh_reg_green, 82 soc_reg_t thresh_reg_yellow, 83 soc_reg_t thresh_reg_red, 84 soc_reg_t thresh_reg_non_tcp, 85 uint32 min_thresh, uint32 max_thresh, 86 int drop_probability, int gain); 87 88 /* 89 * Function: 90 * _bcm_tr_cosw_port_count_get 91 * Purpose: 92 * Returns number of ports in device. 93 * Parameters: 94 * unit - Unit number. 95 * Returns: 96 * BCM_E_XXX 97 */ 98 STATIC int 99 _bcm_tr_cosq_port_count_get(int unit) 100 { 101 int port_count = 44; 102 103 #ifdef BCM_ENDURO_SUPPORT 104 if(SOC_IS_ENDURO (unit)) { 105 port_count = 30; 106 } 107 #endif /* BCM_ENDURO_SUPPORT */ 108 109 return port_count; 110 } 111 112 #ifdef BCM_WARM_BOOT_SUPPORT 113 114 #define BCM_WB_VERSION_1_0 SOC_SCACHE_VERSION(1,0) 115 #define BCM_WB_DEFAULT_VERSION BCM_WB_VERSION_1_0 116 117 /* 118 * Function: 119 * bcm_tr_cosq_sync 120 * Purpose: 121 * Record COSQ module persistent info for Level 2 Warm Boot. 122 * Parameters: 123 * unit - Unit number. 124 * Returns: 125 * BCM_E_XXX 126 */ 127 int 128 bcm_tr_cosq_sync(int unit) 129 { 130 soc_scache_handle_t scache_handle; 131 uint8 *cosq_scache_ptr; 132 uint32 num_cosq; 133 134 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 0); 135 BCM_IF_ERROR_RETURN 136 (_bcm_esw_scache_ptr_get(unit, scache_handle, FALSE, 137 0, &cosq_scache_ptr, 138 BCM_WB_DEFAULT_VERSION, NULL)); 139 140 /* Number COSQ */ 141 num_cosq = _tr_num_cosq[unit]; 142 sal_memcpy(cosq_scache_ptr, &num_cosq, sizeof(num_cosq)); 143 cosq_scache_ptr += sizeof(num_cosq); 144 145 /* Number of hierarchical COSQs added per port */ 146 if (_tr_num_port_cosq[unit] != NULL) { 147 sal_memcpy(cosq_scache_ptr, _tr_num_port_cosq[unit], 148 sizeof(uint8) * _bcm_tr_cosq_port_count_get(unit)); 149 } 150 151 return BCM_E_NONE; 152 } 153 154 /* 155 * Function: 156 * _bcm_tr_cosq_reinit 157 * Purpose: 158 * Recover COSQ software state. 159 * Parameters: 160 * unit - Unit number. 161 * Returns: 162 * BCM_E_XXX 163 */ 164 STATIC int 165 _bcm_tr_cosq_reinit(int unit) 166 { 167 int rv; 168 soc_scache_handle_t scache_handle; 169 uint8 *cosq_scache_ptr; 170 uint32 num_cosq; 171 172 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 0); 173 rv = _bcm_esw_scache_ptr_get(unit, scache_handle, FALSE, 174 0, &cosq_scache_ptr, 175 BCM_WB_DEFAULT_VERSION, NULL); 176 177 if (rv == BCM_E_NOT_FOUND) { 178 cosq_scache_ptr = NULL; 179 } else if (BCM_FAILURE(rv)) { 180 return rv; 181 } 182 183 if (cosq_scache_ptr != NULL) { 184 /* Number COSQ */ 185 sal_memcpy(&num_cosq, cosq_scache_ptr, sizeof(num_cosq)); 186 _tr_num_cosq[unit] = num_cosq; 187 cosq_scache_ptr += sizeof(num_cosq); 188 189 /* Number of hierarchical COSQs added per port */ 190 if (_tr_num_port_cosq[unit] != NULL) { 191 sal_memcpy(_tr_num_port_cosq[unit], cosq_scache_ptr, 192 sizeof(uint8) * _bcm_tr_cosq_port_count_get(unit)); 193 } 194 195 } else { 196 _tr_num_cosq[unit] = _bcm_esw_cosq_config_property_get(unit); 197 } 198 199 return BCM_E_NONE; 200 } 201 #endif /* BCM_WARM_BOOT_SUPPORT */ 202 203 /* 204 * Function: 205 * bcm_cosq_init 206 * Purpose: 207 * Initialize (clear) all COS schedule/mapping state. 208 * Parameters: 209 * unit - StrataSwitch unit number. 210 * Returns: 211 * BCM_E_XXX 212 */ 213 214 int 215 bcm_tr_cosq_init(int unit) 216 { 217 STATIC int _tr_max_cosq = -1; 218 int num_cos; 219 int port_count; 220 #ifdef BCM_WARM_BOOT_SUPPORT 221 int rv; 222 soc_scache_handle_t scache_handle; 223 uint32 cosq_scache_size; 224 uint8 *cosq_scache_ptr; 225 #endif /* BCM_WARM_BOOT_SUPPORT */ 226 227 #ifdef BCM_SCORPION_SUPPORT 228 STATIC int _sc_max_cosq = -1; 229 if (SOC_IS_SC_CQ(unit)) { 230 if (_sc_max_cosq < 0) { 231 _sc_max_cosq = NUM_COS(unit); 232 NUM_COS(unit) = 8; 233 } 234 } else 235 #endif 236 if (_tr_max_cosq < 0) { 237 _tr_max_cosq = NUM_COS(unit); 238 NUM_COS(unit) = 8; 239 } 240 241 if (!SOC_WARM_BOOT(unit)) { /* Cold Boot */ 242 BCM_IF_ERROR_RETURN (bcm_tr_cosq_detach(unit, 0)); 243 } 244 245 num_cos = _bcm_esw_cosq_config_property_get(unit); 246 247 port_count = _bcm_tr_cosq_port_count_get(unit); 248 if (SOC_IS_TR_VL(unit)) { 249 SOC_PBMP_CLEAR(_tr_cosq_24q_ports[unit]); 250 /* Keep track of ports that support 24 (16 + 8) queues */ 251 #ifdef BCM_ENDURO_SUPPORT 252 if(SOC_IS_ENDURO (unit)) { 253 SOC_PBMP_PORT_ADD(_tr_cosq_24q_ports[unit], 26); 254 SOC_PBMP_PORT_ADD(_tr_cosq_24q_ports[unit], 27); 255 SOC_PBMP_PORT_ADD(_tr_cosq_24q_ports[unit], 28); 256 SOC_PBMP_PORT_ADD(_tr_cosq_24q_ports[unit], 29); 257 } else 258 #endif /* BCM_ENDURO_SUPPORT */ 259 { 260 SOC_PBMP_PORT_ADD(_tr_cosq_24q_ports[unit], 2); 261 SOC_PBMP_PORT_ADD(_tr_cosq_24q_ports[unit], 3); 262 SOC_PBMP_PORT_ADD(_tr_cosq_24q_ports[unit], 14); 263 SOC_PBMP_PORT_ADD(_tr_cosq_24q_ports[unit], 15); 264 SOC_PBMP_PORT_ADD(_tr_cosq_24q_ports[unit], 26); 265 SOC_PBMP_PORT_ADD(_tr_cosq_24q_ports[unit], 27); 266 SOC_PBMP_PORT_ADD(_tr_cosq_24q_ports[unit], 28); 267 SOC_PBMP_PORT_ADD(_tr_cosq_24q_ports[unit], 29); 268 SOC_PBMP_PORT_ADD(_tr_cosq_24q_ports[unit], 30); 269 SOC_PBMP_PORT_ADD(_tr_cosq_24q_ports[unit], 31); 270 SOC_PBMP_PORT_ADD(_tr_cosq_24q_ports[unit], 32); 271 SOC_PBMP_PORT_ADD(_tr_cosq_24q_ports[unit], 43); 272 } 273 274 if (_tr_num_port_cosq[unit] == NULL) { 275 _tr_num_port_cosq[unit] = sal_alloc(sizeof(uint8) * port_count, 276 "_tr_num_port_cosq"); 277 } 278 sal_memset(_tr_num_port_cosq[unit], 0, sizeof(uint8) * port_count); 279 } 280 281 #ifdef BCM_WARM_BOOT_SUPPORT 282 /* Warm boot level 2 cache size */ 283 cosq_scache_size = sizeof(uint32); /* Number COSQ */ 284 if (_tr_num_port_cosq[unit] != NULL) { /* Number of COSQs per port */ 285 cosq_scache_size += (sizeof(uint8) * port_count); 286 } 287 288 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 0); 289 rv = _bcm_esw_scache_ptr_get(unit, scache_handle, 290 (0 == SOC_WARM_BOOT(unit)), 291 cosq_scache_size, &cosq_scache_ptr, 292 BCM_WB_DEFAULT_VERSION, NULL); 293 if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) { 294 return rv; 295 } 296 297 if (SOC_WARM_BOOT(unit)) { 298 BCM_IF_ERROR_RETURN(_bcm_tr_cosq_reinit(unit)); 299 num_cos = _tr_num_cosq[unit]; 300 } 301 #endif /* BCM_WARM_BOOT_SUPPORT */ 302 303 return bcm_tr_cosq_config_set(unit, num_cos); 304 } 305 306 /* 307 * Function: 308 * bcm_cosq_detach 309 * Purpose: 310 * Discard all COS schedule/mapping state. 311 * Parameters: 312 * unit - StrataSwitch unit number. 313 * Returns: 314 * BCM_E_XXX 315 */ 316 317 int 318 bcm_tr_cosq_detach(int unit, int software_state_only) 319 { 320 bcm_port_t port; 321 int weights[8]; 322 int cosq; 323 324 if (SOC_IS_TR_VL(unit)) 325 { 326 /* Delete any gports that were added */ 327 328 if (_tr_num_port_cosq[unit]) 329 { 330 if (!software_state_only) 331 { 332 BCM_PBMP_ITER(_tr_cosq_24q_ports[unit], port) 333 { 334 if (_tr_num_port_cosq[unit][port]) 335 { 336 BCM_IF_ERROR_RETURN 337 (_bcm_tr_cosq_gport_delete(unit, port)); 338 } 339 } 340 } 341 342 BCM_IF_ERROR_RETURN 343 (soc_profile_mem_destroy(unit, _tr_cos_map_profile[unit])); 344 sal_free(_tr_cos_map_profile[unit]); 345 _tr_cos_map_profile[unit] = NULL; 346 347 sal_free(_tr_num_port_cosq[unit]); 348 _tr_num_port_cosq[unit] = NULL; 349 } 350 } 351 352 for (cosq = 0; cosq < 8; cosq++) { 353 weights[cosq] = 0; 354 } 355 356 if (!software_state_only) 357 { 358 PBMP_ALL_ITER(unit, port) { 359 if (IS_CPU_PORT(unit, port)) { 360 continue; 361 } 362 363 #ifdef BCM_SCORPION_SUPPORT 364 if (SOC_IS_SC_CQ(unit)) { 365 /* Clear bandwidth settings on port */ 366 for (cosq = 0; cosq < 8; cosq++) { 367 BCM_IF_ERROR_RETURN 368 (bcm_sc_cosq_port_bandwidth_set(unit, port, cosq, 0, 0, 0, 0)); 369 } 370 } else 371 #endif 372 { 373 /* Clear bandwidth settings on port */ 374 for (cosq = 0; cosq < 8; cosq++) { 375 BCM_IF_ERROR_RETURN 376 (bcm_tr_cosq_port_bandwidth_set(unit, port, cosq, 0, 0, 0, 0)); 377 } 378 } 379 /* Clear scheduling settings on port */ 380 BCM_IF_ERROR_RETURN 381 (_bcm_tr_cosq_port_sched_set(unit, 382 ESCONFIGr, COSWEIGHTSr, MINSPCONFIGr, 383 port, 0, 8, weights, 384 BCM_COSQ_WEIGHTED_ROUND_ROBIN)); 385 /* Clear discard settings on port */ 386 387 if (SOC_IS_TR_VL(unit)) { 388 for (cosq = 0; cosq < 8; cosq++) { 389 BCM_IF_ERROR_RETURN 390 (_bcm_tr_cosq_discard_set(unit, port, 391 BCM_COSQ_DISCARD_COLOR_ALL | 392 BCM_COSQ_DISCARD_NONTCP, cosq, 393 WREDCONFIG_PACKETr, 394 WREDPARAM_PACKETr, 395 WREDPARAM_YELLOW_PACKETr, 396 WREDPARAM_RED_PACKETr, 397 WREDPARAM_NONTCP_PACKETr, 398 TR_PACKET_FIELD_MAX(unit), 399 TR_PACKET_FIELD_MAX(unit), 100, 0)); 400 } 401 } 402 } 403 } 404 405 #ifdef BCM_SCORPION_SUPPORT 406 if (SOC_IS_SC_CQ(unit)) { 407 BCM_IF_ERROR_RETURN (_bcm_sc_cosq_discard_all_disable(unit)); 408 } else 409 #endif 410 { 411 /* Disable WRED on all cosq level */ 412 BCM_IF_ERROR_RETURN (bcm_tr_cosq_discard_set(unit, 0)); 413 } 414 415 return BCM_E_NONE; 416 } 417 418 /* 419 * Function: 420 * bcm_cosq_config_set 421 * Purpose: 422 * Set the number of COS queues 423 * Parameters: 424 * unit - Unit number. 425 * numq - number of COS queues (1-8). 426 * Returns: 427 * BCM_E_XXX 428 */ 429 430 int 431 bcm_tr_cosq_config_set(int unit, int numq) 432 { 433 int cos, prio, ratio, remain; 434 uint32 index, minsp; 435 soc_mem_t mem = PORT_COS_MAPm; 436 int entry_words = sizeof(port_cos_map_entry_t) / sizeof(uint32); 437 bcm_pbmp_t ports; 438 bcm_port_t port; 439 port_cos_map_entry_t cos_map_array[TR_COS_MAP_ENTRIES_PER_SET]; 440 void *entries[1]; 441 442 /* Validate cosq num */ 443 if (numq < 1) { 444 return BCM_E_PARAM; 445 } 446 447 /* Map the eight 802.1 priority levels to the active cosqs */ 448 if (numq > 8) { 449 numq = 8; 450 } 451 452 if (SOC_IS_SHADOW(unit)) { 453 return BCM_E_NONE; 454 } 455 456 sal_memset(cos_map_array, 0, 457 TR_COS_MAP_ENTRIES_PER_SET * sizeof(port_cos_map_entry_t)); 458 459 if (_tr_cos_map_profile[unit] == NULL) { 460 _tr_cos_map_profile[unit] = sal_alloc(sizeof(soc_profile_mem_t), 461 "COS_MAP Profile Mem"); 462 if (_tr_cos_map_profile[unit] == NULL) { 463 return BCM_E_MEMORY; 464 } 465 soc_profile_mem_t_init(_tr_cos_map_profile[unit]); 466 } 467 468 /* Create profile table cache (or re-init if it already exists) */ 469 SOC_IF_ERROR_RETURN(soc_profile_mem_create(unit, &mem, &entry_words, 1, 470 _tr_cos_map_profile[unit])); 471 472 if (SOC_WARM_BOOT(unit)) { /* Warm Boot */ 473 int i; 474 uint32 val; 475 476 /* Gather reference count for cosq map profile table */ 477 BCM_PBMP_ASSIGN(ports, PBMP_ALL(unit)); 478 PBMP_ITER(ports, port) { 479 SOC_IF_ERROR_RETURN(READ_COS_MAP_SELr(unit, port, &val)); 480 index = soc_reg_field_get(unit, COS_MAP_SELr, val, SELECTf); 481 index *= TR_COS_MAP_ENTRIES_PER_SET; 482 for (i = 0; i < TR_COS_MAP_ENTRIES_PER_SET; i++) { 483 SOC_PROFILE_MEM_REFERENCE(unit, _tr_cos_map_profile[unit], 484 index + i, 1); 485 SOC_PROFILE_MEM_ENTRIES_PER_SET(unit, 486 _tr_cos_map_profile[unit], 487 index + i, 488 TR_COS_MAP_ENTRIES_PER_SET); 489 } 490 #ifndef BCM_COSQ_HIGIG_MAP_DISABLE 491 if (IS_HG_PORT(unit, port) || port == CMIC_PORT(unit)) { 492 SOC_IF_ERROR_RETURN(READ_ICOS_MAP_SELr(unit, port, &val)); 493 index = soc_reg_field_get(unit, ICOS_MAP_SELr, val, SELECTf); 494 index *= TR_COS_MAP_ENTRIES_PER_SET; 495 for (i = 0; i < TR_COS_MAP_ENTRIES_PER_SET; i++) { 496 SOC_PROFILE_MEM_REFERENCE(unit, _tr_cos_map_profile[unit], 497 index + i, 1); 498 SOC_PROFILE_MEM_ENTRIES_PER_SET(unit, 499 _tr_cos_map_profile[unit], 500 index + i, 501 TR_COS_MAP_ENTRIES_PER_SET); 502 } 503 } 504 #endif /* BCM_COSQ_HIGIG_MAP_DISABLE */ 505 } 506 } else { /* Cold Boot */ 507 508 entries[0] = &cos_map_array; 509 510 ratio = 8 / numq; 511 remain = 8 % numq; 512 cos = 0; 513 for (prio = 0; prio < 8; prio++) { 514 soc_mem_field32_set(unit, PORT_COS_MAPm, 515 &cos_map_array[prio], COSf, cos); 516 if (soc_mem_field_valid(unit,PORT_COS_MAPm,HG_COSf)) { 517 soc_mem_field32_set(unit, PORT_COS_MAPm, 518 &cos_map_array[prio], HG_COSf, 0); 519 } 520 521 if ((prio + 1) == (((cos + 1) * ratio) + 522 ((remain < (numq - cos)) ? 0 : 523 (remain - (numq - cos) + 1)))) { 524 cos++; 525 } 526 } 527 528 /* Map remaining internal priority levels to highest priority cosq */ 529 cos = numq - 1; 530 for (prio = 8; prio < 16; prio++) { 531 soc_mem_field32_set(unit, PORT_COS_MAPm, 532 &cos_map_array[prio], COSf, cos); 533 if (soc_mem_field_valid(unit,PORT_COS_MAPm,HG_COSf)) { 534 soc_mem_field32_set(unit, PORT_COS_MAPm, 535 &cos_map_array[prio], HG_COSf, 0); 536 } 537 } 538 539 /* Map internal priority levels to CPU CoS queues */ 540 BCM_IF_ERROR_RETURN(_bcm_esw_cpu_cosq_mapping_default_set(unit, numq)); 541 542 /* Add a profile mem entry for each port */ 543 BCM_PBMP_ASSIGN(ports, PBMP_ALL(unit)); 544 PBMP_ITER(ports, port) { 545 SOC_IF_ERROR_RETURN 546 (soc_profile_mem_add(unit, _tr_cos_map_profile[unit], 547 (void *) &entries, 548 TR_COS_MAP_ENTRIES_PER_SET, 549 &index)); 550 SOC_IF_ERROR_RETURN(soc_reg_field32_modify(unit, COS_MAP_SELr, port, 551 SELECTf, 552 (index / TR_COS_MAP_ENTRIES_PER_SET))); 553 #ifndef BCM_COSQ_HIGIG_MAP_DISABLE 554 if (IS_HG_PORT(unit, port) || port == CMIC_PORT(unit)) { 555 SOC_IF_ERROR_RETURN 556 (soc_profile_mem_add(unit, _tr_cos_map_profile[unit], 557 (void *) &entries, 558 TR_COS_MAP_ENTRIES_PER_SET, 559 &index)); 560 SOC_IF_ERROR_RETURN(soc_reg_field32_modify(unit, ICOS_MAP_SELr, port, 561 SELECTf, 562 (index / TR_COS_MAP_ENTRIES_PER_SET))); 563 } 564 #endif 565 } 566 567 #ifdef BCM_COSQ_HIGIG_MAP_DISABLE 568 /* identity mapping for higig ports */ 569 570 /* map prio0->cos0, prio1->cos1, ... , prio7->cos7 */ 571 for (prio = 0; prio < 8; prio++) { 572 soc_mem_field32_set(unit, PORT_COS_MAPm, 573 &cos_map_array[prio], COSf, prio); 574 if (soc_mem_field_valid(unit,PORT_COS_MAPm,HG_COSf)) { 575 soc_mem_field32_set(unit, PORT_COS_MAPm, 576 &cos_map_array[prio], HG_COSf, 0); 577 } 578 } 579 /* Map remaining internal priority levels to highest priority cosq */ 580 for (prio = 8; prio < 16; prio++) { 581 soc_mem_field32_set(unit, PORT_COS_MAPm, 582 &cos_map_array[prio], COSf, 7); 583 if (soc_mem_field_valid(unit,PORT_COS_MAPm,HG_COSf)) { 584 soc_mem_field32_set(unit, PORT_COS_MAPm, 585 &cos_map_array[prio], HG_COSf, 0); 586 } 587 } 588 589 PBMP_ITER(ports, port) { 590 if (IS_HG_PORT(unit, port) || port == CMIC_PORT(unit)) { 591 SOC_IF_ERROR_RETURN 592 (soc_profile_mem_add(unit, _tr_cos_map_profile[unit], 593 (void *) &entries, 594 TR_COS_MAP_ENTRIES_PER_SET, &index)); 595 soc_reg_field32_modify(unit, ICOS_MAP_SELr, port, 596 SELECTf, 597 (index / TR_COS_MAP_ENTRIES_PER_SET)); 598 } 599 } 600 #endif 601 602 /* Always strict priority for SC and QM COS queues */ 603 PBMP_ITER(ports, port) { 604 #ifdef BCM_SCORPION_SUPPORT 605 if (SOC_IS_SC_CQ(unit)) { 606 /* COS8 and COS9 not configurable on Scorpion */ 607 continue; 608 } 609 #endif 610 SOC_IF_ERROR_RETURN 611 (READ_MINSPCONFIGr(unit, port, &minsp)); 612 soc_reg_field_set(unit, MINSPCONFIGr, &minsp, COS8_IS_SPf, 1); 613 soc_reg_field_set(unit, MINSPCONFIGr, &minsp, COS9_IS_SPf, 1); 614 SOC_IF_ERROR_RETURN 615 (WRITE_MINSPCONFIGr(unit, port, minsp)); 616 } 617 } 618 619 _tr_num_cosq[unit] = numq; 620 621 #ifdef BCM_WARM_BOOT_SUPPORT 622 SOC_CONTROL_LOCK(unit); 623 SOC_CONTROL(unit)->scache_dirty = 1; 624 SOC_CONTROL_UNLOCK(unit); 625 #endif 626 627 return BCM_E_NONE; 628 } 629 630 /* 631 * Function: 632 * bcm_cosq_config_get 633 * Purpose: 634 * Get the number of cos queues 635 * Parameters: 636 * unit - StrataSwitch unit number. 637 * numq - (Output) number of cosq 638 * Returns: 639 * BCM_E_XXX 640 */ 641 642 int 643 bcm_tr_cosq_config_get(int unit, int *numq) 644 { 645 if (_tr_num_cosq[unit] == 0) { 646 return BCM_E_INIT; 647 } 648 649 if (numq != NULL) { 650 *numq = _tr_num_cosq[unit]; 651 } 652 653 return BCM_E_NONE; 654 } 655 656 /* 657 * Function: 658 * bcm_cosq_mapping_set 659 * Purpose: 660 * Set which cosq a given priority should fall into 661 * Parameters: 662 * unit - StrataSwitch unit number. 663 * priority - Priority value to map 664 * cosq - COS queue to map to 665 * Returns: 666 * BCM_E_XXX 667 */ 668 669 int 670 bcm_tr_cosq_mapping_set(int unit, bcm_port_t port, 671 bcm_cos_t priority, bcm_cos_queue_t cosq) 672 { 673 uint32 val, old_index, new_index; 674 int i; 675 port_cos_map_entry_t cos_map_array[TR_COS_MAP_ENTRIES_PER_SET], *entry_p; 676 void *entries[1]; 677 bcm_pbmp_t ports; 678 bcm_port_t local_port; 679 680 if (priority < 0 || priority >= 16) { 681 return (BCM_E_PARAM); 682 } 683 684 if (cosq < 0 || cosq >= 8) { 685 return (BCM_E_PARAM); 686 } 687 688 if (port == -1) { /* all ports */ 689 BCM_PBMP_ASSIGN(ports, PBMP_ALL(unit)); 690 } else { 691 if (BCM_GPORT_IS_SET(port)) { 692 BCM_IF_ERROR_RETURN( 693 bcm_esw_port_local_get(unit, port, &local_port)); 694 } else { 695 local_port = port; 696 } 697 698 if (!SOC_PORT_VALID(unit, local_port) || !IS_ALL_PORT(unit, local_port)) { 699 return BCM_E_PORT; 700 } 701 BCM_PBMP_CLEAR(ports); 702 BCM_PBMP_PORT_ADD(ports, local_port); 703 } 704 705 entries[0] = &cos_map_array; 706 707 PBMP_ITER(ports, local_port) { 708 SOC_IF_ERROR_RETURN(READ_COS_MAP_SELr(unit, local_port, &val)); 709 old_index = soc_reg_field_get(unit, COS_MAP_SELr, val, SELECTf); 710 old_index *= TR_COS_MAP_ENTRIES_PER_SET; 711 712 /* get current mapping profile values */ 713 for (i = 0; i < TR_COS_MAP_ENTRIES_PER_SET; i++) { 714 entry_p = SOC_PROFILE_MEM_ENTRY(unit, _tr_cos_map_profile[unit], 715 port_cos_map_entry_t *, (old_index + i)); 716 memcpy(&cos_map_array[i], entry_p, sizeof(*entry_p)); 717 } 718 soc_mem_field32_set(unit, PORT_COS_MAPm, 719 &cos_map_array[priority], COSf, cosq); 720 SOC_IF_ERROR_RETURN 721 (soc_profile_mem_add(unit, _tr_cos_map_profile[unit], 722 (void *) &entries, 723 TR_COS_MAP_ENTRIES_PER_SET, 724 &new_index)); 725 SOC_IF_ERROR_RETURN 726 (soc_reg_field32_modify(unit, COS_MAP_SELr, local_port, 727 SELECTf, 728 new_index / TR_COS_MAP_ENTRIES_PER_SET)); 729 SOC_IF_ERROR_RETURN 730 (soc_profile_mem_delete(unit, _tr_cos_map_profile[unit], old_index)); 731 732 #ifndef BCM_COSQ_HIGIG_MAP_DISABLE 733 if (IS_HG_PORT(unit, local_port) || local_port == CMIC_PORT(unit)) { 734 SOC_IF_ERROR_RETURN 735 (soc_profile_mem_add(unit, _tr_cos_map_profile[unit], 736 (void *) &entries, 737 TR_COS_MAP_ENTRIES_PER_SET, 738 &new_index)); 739 SOC_IF_ERROR_RETURN 740 (soc_reg_field32_modify(unit, ICOS_MAP_SELr, local_port, 741 SELECTf, 742 new_index / TR_COS_MAP_ENTRIES_PER_SET)); 743 SOC_IF_ERROR_RETURN 744 (soc_profile_mem_delete(unit, _tr_cos_map_profile[unit], old_index)); 745 } 746 #endif 747 } 748 return BCM_E_NONE; 749 } 750 751 /* 752 * Function: 753 * bcm_cosq_mapping_get 754 * Purpose: 755 * Determine which COS queue a given priority currently maps to. 756 * Parameters: 757 * unit - StrataSwitch unit number. 758 * priority - Priority value 759 * cosq - (Output) COS queue number 760 * Returns: 761 * BCM_E_XXX 762 */ 763 764 int 765 bcm_tr_cosq_mapping_get(int unit, bcm_port_t port, 766 bcm_cos_t priority, bcm_cos_queue_t *cosq) 767 { 768 uint32 val; 769 int index; 770 port_cos_map_entry_t *entry_p; 771 bcm_port_t local_port; 772 773 if (priority < 0 || priority >= 16) { 774 return (BCM_E_PARAM); 775 } 776 777 if (port == -1) { 778 local_port = REG_PORT_ANY; 779 } else { 780 if (BCM_GPORT_IS_SET(port)) { 781 BCM_IF_ERROR_RETURN( 782 bcm_esw_port_local_get(unit, port, &local_port)); 783 } else { 784 local_port = port; 785 } 786 787 if (!SOC_PORT_VALID(unit, local_port) || !IS_ALL_PORT(unit, local_port)) { 788 return BCM_E_PORT; 789 } 790 } 791 792 SOC_IF_ERROR_RETURN(READ_COS_MAP_SELr(unit, local_port, &val)); 793 index = soc_reg_field_get(unit, COS_MAP_SELr, val, SELECTf); 794 index *= TR_COS_MAP_ENTRIES_PER_SET; 795 796 entry_p = SOC_PROFILE_MEM_ENTRY(unit, _tr_cos_map_profile[unit], 797 port_cos_map_entry_t *, 798 (index + priority)); 799 *cosq = soc_mem_field32_get(unit, PORT_COS_MAPm, entry_p, COSf); 800 return BCM_E_NONE; 801 } 802 803 #if defined(BCM_ENDURO_SUPPORT) || defined(BCM_TRIUMPH_SUPPORT) 804 STATIC int 805 _bcm_tr_cpu_cosq_port_bandwidth_set(int unit, bcm_port_t port, 806 bcm_cos_queue_t cosq, 807 uint32 kbits_sec_min, 808 uint32 kbits_sec_max, 809 uint32 kbits_sec_burst, 810 uint32 flags) 811 { 812 uint32 regval; 813 uint32 bucket_val = 0; 814 uint64 regval_64; 815 uint32 refresh_rate, bucketsize, granularity = 3, meter_flags = 0; 816 int refresh_bitsize, bucket_bitsize; 817 818 if(SOC_IS_RCPU_ONLY(unit)) { 819 return 0; 820 } 821 822 /* 823 * To set the new Bandwidth settings, the procedure adopted is 824 * a. reset MAXBUCKETCONFIG, MINBUCKETCONFIG, MAXBUCKET,MINBUCKET 825 * b. update MAXBUCKETCONFIG and MINBUCKETCONFIG with new values passed 826 * c. if MISCCONFIG.METERING_CLK_EN not set before, enable it. 827 */ 828 if (SOC_IS_ENDURO(unit)) { 829 meter_flags = flags & BCM_COSQ_BW_PACKET_MODE ? 830 _BCM_XGS_METER_FLAG_PACKET_MODE : 0; 831 } 832 833 BCM_IF_ERROR_RETURN(READ_MISCCONFIGr(unit, ®val)); 834 if (soc_reg_field_get(unit, MISCCONFIGr, regval, ITU_MODE_SELf)) { 835 meter_flags |= _BCM_XGS_METER_FLAG_NON_LINEAR; 836 } 837 meter_flags |= _BCM_XGS_METER_FLAG_GRANULARITY; 838 839 /* Disable egress metering for this port */ 840 if (SOC_REG_IS_VALID(unit, CPUMAXBUCKETCONFIG_64r)) { 841 BCM_IF_ERROR_RETURN(READ_CPUMAXBUCKETCONFIG_64r(unit, cosq, ®val_64)); 842 soc_reg64_field32_set(unit, CPUMAXBUCKETCONFIG_64r, ®val_64, MAX_REFRESHf, 0); 843 soc_reg64_field32_set(unit, CPUMAXBUCKETCONFIG_64r, ®val_64, MAX_THDf, 0); 844 BCM_IF_ERROR_RETURN(WRITE_CPUMAXBUCKETCONFIG_64r(unit, cosq, regval_64)); 845 } 846 847 /*reset the MAXBUCKET register*/ 848 if (SOC_REG_IS_VALID(unit, CPUMAXBUCKETr)) { 849 soc_reg_field_set(unit, CPUMAXBUCKETr, &bucket_val, PKT_MAX_BUCKETf, 0); 850 soc_reg_field_set(unit, CPUMAXBUCKETr, &bucket_val, OUT_PROFILE_FLAGf, 0); 851 BCM_IF_ERROR_RETURN(WRITE_CPUMAXBUCKETr(unit, cosq, bucket_val)); 852 } 853 854 refresh_bitsize = 855 soc_reg_field_length(unit, MINBUCKETCONFIG_64r, MIN_REFRESHf); 856 bucket_bitsize = 857 soc_reg_field_length(unit, MINBUCKETCONFIG_64r, MIN_THDf); 858 859 BCM_IF_ERROR_RETURN 860 (_bcm_xgs_kbits_to_bucket_encoding(kbits_sec_min, kbits_sec_min, 861 meter_flags, refresh_bitsize, bucket_bitsize, 862 &refresh_rate, &bucketsize, &granularity)); 863 864 if (SOC_REG_IS_VALID(unit, CPUMAXBUCKETCONFIG_64r)) { 865 refresh_bitsize = 866 soc_reg_field_length(unit, CPUMAXBUCKETCONFIG_64r, MAX_REFRESHf); 867 bucket_bitsize = 868 soc_reg_field_length(unit, CPUMAXBUCKETCONFIG_64r, MAX_THDf); 869 } 870 871 BCM_IF_ERROR_RETURN 872 (_bcm_xgs_kbits_to_bucket_encoding(kbits_sec_max, kbits_sec_burst, 873 meter_flags, refresh_bitsize, bucket_bitsize, 874 &refresh_rate, &bucketsize, &granularity)); 875 876 COMPILER_64_ZERO(regval_64); 877 if (SOC_REG_IS_VALID(unit, CPUMAXBUCKETCONFIG_64r)) { 878 soc_reg64_field32_set(unit, CPUMAXBUCKETCONFIG_64r, ®val_64, 879 METER_GRANf, granularity); 880 soc_reg64_field32_set(unit, CPUMAXBUCKETCONFIG_64r, ®val_64, 881 MAX_REFRESHf, refresh_rate); 882 soc_reg64_field32_set(unit, CPUMAXBUCKETCONFIG_64r, ®val_64, MAX_THDf, 883 bucketsize); 884 if (SOC_IS_ENDURO(unit)) { 885 soc_reg64_field32_set(unit, CPUMAXBUCKETCONFIG_64r, ®val_64, MODEf, 886 (flags & BCM_COSQ_BW_PACKET_MODE) ? 1 : 0); 887 } 888 BCM_IF_ERROR_RETURN(WRITE_CPUMAXBUCKETCONFIG_64r(unit, cosq, regval_64)); 889 } 890 /* MISCCONFIG.METERING_CLK_EN is set by chip init */ 891 892 return BCM_E_NONE; 893 } 894 #endif 895 896 897 STATIC int 898 _bcm_tr_cosq_bucket_set(int unit, bcm_port_t port, 899 bcm_cos_queue_t cosq, 900 uint32 kbits_sec_min, /* kbps or packet/second */ 901 uint32 kbits_sec_max, /* kbps or packet/second */ 902 uint32 kbits_burst_min, 903 uint32 kbits_burst_max, 904 uint32 flags) 905 { 906 uint32 regval; 907 uint32 bucket_val = 0; 908 uint64 regval_64; 909 uint32 refresh_rate, bucketsize, granularity = 3, meter_flags = 0; 910 int refresh_bitsize, bucket_bitsize; 911 912 if(SOC_IS_RCPU_ONLY(unit)) { 913 return 0; 914 } 915 916 #if defined(BCM_ENDURO_SUPPORT) || defined(BCM_TRIUMPH_SUPPORT) 917 if (IS_CPU_PORT(unit, port)) { 918 return _bcm_tr_cpu_cosq_port_bandwidth_set(unit, port, cosq, 919 kbits_sec_min, kbits_sec_max, kbits_burst_max, flags); 920 } 921 #endif /* BCM_ENDURO_SUPPORT */ 922 923 /* 924 * To set the new Bandwidth settings, the procedure adopted is 925 * a. reset MAXBUCKETCONFIG, MINBUCKETCONFIG, MAXBUCKET,MINBUCKET 926 * b. update MAXBUCKETCONFIG and MINBUCKETCONFIG with new values passed 927 * c. if MISCCONFIG.METERING_CLK_EN not set before, enable it. 928 */ 929 930 BCM_IF_ERROR_RETURN(READ_MISCCONFIGr(unit, ®val)); 931 if (soc_reg_field_get(unit, MISCCONFIGr, regval, ITU_MODE_SELf)) { 932 meter_flags |= _BCM_XGS_METER_FLAG_NON_LINEAR; 933 } 934 meter_flags |= _BCM_XGS_METER_FLAG_GRANULARITY; 935 936 /* Disable egress metering for this port */ 937 BCM_IF_ERROR_RETURN(READ_MAXBUCKETCONFIG_64r(unit, port, cosq, ®val_64)); 938 soc_reg64_field32_set(unit, MAXBUCKETCONFIG_64r, ®val_64, MAX_REFRESHf, 0); 939 soc_reg64_field32_set(unit, MAXBUCKETCONFIG_64r, ®val_64, MAX_THDf, 0); 940 BCM_IF_ERROR_RETURN(WRITE_MAXBUCKETCONFIG_64r(unit, port, cosq, regval_64)); 941 942 BCM_IF_ERROR_RETURN(READ_MINBUCKETCONFIG_64r(unit, port, cosq, ®val_64)); 943 soc_reg64_field32_set(unit, MINBUCKETCONFIG_64r, ®val_64, MIN_REFRESHf, 0); 944 soc_reg64_field32_set(unit, MINBUCKETCONFIG_64r, ®val_64, MIN_THDf, 0); 945 BCM_IF_ERROR_RETURN(WRITE_MINBUCKETCONFIG_64r(unit, port, cosq, regval_64)); 946 947 /*reset the MAXBUCKET register*/ 948 soc_reg_field_set(unit, MAXBUCKETr, &bucket_val, MAX_BUCKETf, 0); 949 soc_reg_field_set(unit, MAXBUCKETr, &bucket_val, OUT_PROFILE_FLAGf, 0); 950 BCM_IF_ERROR_RETURN(WRITE_MAXBUCKETr(unit, port, cosq, bucket_val)); 951 952 /*reset the MINBUCKET register value*/ 953 soc_reg_field_set(unit, MINBUCKETr, &bucket_val, MIN_BUCKETf, 0); 954 soc_reg_field_set(unit, MINBUCKETr, &bucket_val, OUT_PROFILE_FLAGf, 0); 955 BCM_IF_ERROR_RETURN(WRITE_MINBUCKETr(unit, port, cosq, bucket_val)); 956 957 refresh_bitsize = 958 soc_reg_field_length(unit, MINBUCKETCONFIG_64r, MIN_REFRESHf); 959 bucket_bitsize = 960 soc_reg_field_length(unit, MINBUCKETCONFIG_64r, MIN_THDf); 961 962 BCM_IF_ERROR_RETURN 963 (_bcm_xgs_kbits_to_bucket_encoding(kbits_sec_min, kbits_burst_min, 964 meter_flags, refresh_bitsize, bucket_bitsize, 965 &refresh_rate, &bucketsize, &granularity)); 966 967 COMPILER_64_ZERO(regval_64); 968 soc_reg64_field32_set(unit, MINBUCKETCONFIG_64r, ®val_64, 969 METER_GRANf, granularity); 970 soc_reg64_field32_set(unit, MINBUCKETCONFIG_64r, ®val_64, 971 MIN_REFRESHf, refresh_rate); 972 soc_reg64_field32_set(unit, MINBUCKETCONFIG_64r, 973 ®val_64, MIN_THDf, bucketsize); 974 BCM_IF_ERROR_RETURN 975 (WRITE_MINBUCKETCONFIG_64r(unit, port, cosq, regval_64)); 976 977 refresh_bitsize = 978 soc_reg_field_length(unit, MAXBUCKETCONFIG_64r, MAX_REFRESHf); 979 bucket_bitsize = 980 soc_reg_field_length(unit, MAXBUCKETCONFIG_64r, MAX_THDf); 981 982 BCM_IF_ERROR_RETURN 983 (_bcm_xgs_kbits_to_bucket_encoding(kbits_sec_max, kbits_burst_max, 984 meter_flags, refresh_bitsize, bucket_bitsize, 985 &refresh_rate, &bucketsize, &granularity)); 986 987 COMPILER_64_ZERO(regval_64); 988 soc_reg64_field32_set(unit, MAXBUCKETCONFIG_64r, ®val_64, 989 METER_GRANf, granularity); 990 soc_reg64_field32_set(unit, MAXBUCKETCONFIG_64r, ®val_64, 991 MAX_REFRESHf, refresh_rate); 992 soc_reg64_field32_set(unit, MAXBUCKETCONFIG_64r, ®val_64, MAX_THDf, 993 bucketsize); 994 BCM_IF_ERROR_RETURN(WRITE_MAXBUCKETCONFIG_64r(unit, port, cosq, regval_64)); 995 996 /* MISCCONFIG.METERING_CLK_EN is set by chip init */ 997 998 return BCM_E_NONE; 999 } 1000 1001 STATIC int 1002 _bcm_tr_cosq_bucket_get(int unit, bcm_port_t port, 1003 bcm_cos_queue_t cosq, 1004 uint32 *kbits_sec_min, 1005 uint32 *kbits_sec_max, 1006 uint32 *kbits_min_burst, 1007 uint32 *kbits_max_burst, 1008 uint32 *flags) 1009 { 1010 uint32 regval; 1011 uint64 regval_64; 1012 uint32 refresh_rate = 0, bucketsize = 0, 1013 granularity = 3, meter_flags = 0; 1014 1015 if (!kbits_sec_min || !kbits_sec_max || !kbits_min_burst 1016 || !kbits_max_burst || !flags) { 1017 return (BCM_E_PARAM); 1018 } 1019 1020 *flags = 0; 1021 BCM_IF_ERROR_RETURN(READ_MAXBUCKETCONFIG_64r(unit, port, cosq, ®val_64)); 1022 granularity = soc_reg64_field32_get(unit, MAXBUCKETCONFIG_64r, 1023 regval_64, METER_GRANf); 1024 refresh_rate = soc_reg64_field32_get(unit, MAXBUCKETCONFIG_64r, 1025 regval_64, MAX_REFRESHf); 1026 bucketsize = soc_reg64_field32_get(unit, MAXBUCKETCONFIG_64r, 1027 regval_64, MAX_THDf); 1028 1029 BCM_IF_ERROR_RETURN(READ_MISCCONFIGr(unit, ®val)); 1030 if (soc_reg_field_get(unit, MISCCONFIGr, regval, ITU_MODE_SELf)) { 1031 meter_flags |= _BCM_XGS_METER_FLAG_NON_LINEAR; 1032 } 1033 1034 meter_flags |= _BCM_XGS_METER_FLAG_GRANULARITY; 1035 1036 1037 1038 BCM_IF_ERROR_RETURN 1039 (_bcm_xgs_bucket_encoding_to_kbits(refresh_rate, bucketsize, 1040 granularity, meter_flags, 1041 kbits_sec_max, kbits_max_burst)); 1042 1043 BCM_IF_ERROR_RETURN(READ_MINBUCKETCONFIG_64r(unit, port, cosq, ®val_64)); 1044 1045 granularity = soc_reg64_field32_get(unit, MINBUCKETCONFIG_64r, 1046 regval_64, METER_GRANf); 1047 refresh_rate = soc_reg64_field32_get(unit, MINBUCKETCONFIG_64r, 1048 regval_64, MIN_REFRESHf); 1049 bucketsize = soc_reg64_field32_get(unit, MINBUCKETCONFIG_64r, 1050 regval_64, MIN_THDf); 1051 BCM_IF_ERROR_RETURN 1052 (_bcm_xgs_bucket_encoding_to_kbits(refresh_rate, bucketsize, 1053 granularity, meter_flags, 1054 kbits_sec_min, kbits_min_burst)); 1055 1056 return BCM_E_NONE; 1057 } 1058 1059 1060 int 1061 bcm_tr_cosq_port_bandwidth_set(int unit, bcm_port_t port, 1062 bcm_cos_queue_t cosq, 1063 uint32 kbits_sec_min, 1064 uint32 kbits_sec_max, 1065 uint32 kbits_sec_burst, 1066 uint32 flags) 1067 { 1068 1069 /*keep place with original*/ 1070 return _bcm_tr_cosq_bucket_set(unit, port, cosq, kbits_sec_min, kbits_sec_max, 1071 kbits_sec_min, kbits_sec_burst, flags); 1072 } 1073 1074 int 1075 bcm_tr_cosq_port_bandwidth_get(int unit, bcm_port_t port, 1076 bcm_cos_queue_t cosq, 1077 uint32 *kbits_sec_min, 1078 uint32 *kbits_sec_max, 1079 uint32 *kbits_sec_burst, 1080 uint32 *flags) 1081 { 1082 1083 uint32 kbits_min_burst; /* Placeholder, since burst is unused for min */ 1084 1085 BCM_IF_ERROR_RETURN(_bcm_tr_cosq_bucket_get(unit, port, cosq, 1086 kbits_sec_min, kbits_sec_max, &kbits_min_burst, 1087 kbits_sec_burst, flags)); 1088 return BCM_E_NONE; 1089 1090 } 1091 1092 STATIC int 1093 _bcm_tr_cosq_port_packet_bandwidth_set(int unit, bcm_port_t port, 1094 bcm_cos_queue_t cosq, 1095 int pps, int burst) 1096 1097 { 1098 uint32 regval, max_config_addr, max_addr; 1099 soc_reg_t maxbucket_config_reg, maxbucket_reg; 1100 soc_field_t refresh_f, thd_sel_f, bucket_f; 1101 1102 if (cosq < 0) { 1103 maxbucket_config_reg = CPUPKTPORTMAXBUCKETCONFIGr; 1104 maxbucket_reg = CPUPKTPORTMAXBUCKETr; 1105 refresh_f = PKT_PORT_MAX_REFRESHf; 1106 thd_sel_f = PKT_PORT_MAX_THD_SELf; 1107 bucket_f = PKT_PORT_MAX_BUCKETf; 1108 cosq = 0; 1109 } else { 1110 maxbucket_config_reg = CPUPKTMAXBUCKETCONFIGr; 1111 maxbucket_reg = CPUPKTMAXBUCKETr; 1112 refresh_f = PKT_MAX_REFRESHf; 1113 thd_sel_f = PKT_MAX_THD_SELf; 1114 bucket_f = PKT_MAX_BUCKETf; 1115 } 1116 1117 /* 1118 * To set the new Bandwidth settings, the procedure adopted is 1119 * a. reset MAXBUCKETCONFIG and MAXBUCKET 1120 * b. update MAXBUCKETCONFIG with new values passed 1121 * c. if MISCCONFIG.METERING_CLK_EN not set before, enable it. 1122 */ 1123 1124 /* Disable egress metering */ 1125 max_config_addr = soc_reg_addr(unit, maxbucket_config_reg, port, cosq); 1126 BCM_IF_ERROR_RETURN(soc_reg32_read(unit, max_config_addr, ®val)); 1127 soc_reg_field_set(unit, maxbucket_config_reg, ®val, refresh_f, 0); 1128 soc_reg_field_set(unit, maxbucket_config_reg, ®val, thd_sel_f, 0); 1129 BCM_IF_ERROR_RETURN(soc_reg32_write(unit, max_config_addr, regval)); 1130 1131 /* reset the MAXBUCKET register*/ 1132 max_addr = soc_reg_addr(unit, maxbucket_reg, port, cosq); 1133 BCM_IF_ERROR_RETURN(soc_reg32_read(unit, max_addr, ®val)); 1134 soc_reg_field_set(unit, maxbucket_reg, ®val, bucket_f, 0); 1135 soc_reg_field_set(unit, maxbucket_reg, ®val, OUT_PROFILE_FLAGf, 0); 1136 BCM_IF_ERROR_RETURN(soc_reg32_write(unit, max_addr, regval)); 1137 1138 /* Check packets-per second upper limit */ 1139 if (pps > TR_PKT_REFRESH_MAX(unit)) { 1140 pps = TR_PKT_REFRESH_MAX(unit); 1141 } 1142 1143 /* Check burst upper limit */ 1144 if (burst > TR_PKT_THD_MAX(unit)) { 1145 burst = TR_PKT_THD_MAX(unit); 1146 } 1147 1148 BCM_IF_ERROR_RETURN(soc_reg32_read(unit, max_config_addr, ®val)); 1149 soc_reg_field_set(unit, maxbucket_config_reg, ®val, refresh_f, pps); 1150 soc_reg_field_set(unit, maxbucket_config_reg, 1151 ®val, thd_sel_f, burst); 1152 BCM_IF_ERROR_RETURN(soc_reg32_write(unit, max_config_addr, regval)); 1153 1154 /* MISCCONFIG.METERING_CLK_EN is set by chip init */ 1155 1156 return BCM_E_NONE; 1157 } 1158 1159 #ifdef BCM_ENDURO_SUPPORT 1160 1161 STATIC int 1162 _bcm_en_cosq_port_packet_bandwidth_set(int unit, bcm_port_t port, 1163 bcm_cos_queue_t cosq, 1164 int pps, int burst, uint32 flags) 1165 { 1166 uint64 regval_64; 1167 uint32 refresh_rate, bucketsize, granularity = 3, meter_flags = 0; 1168 int refresh_bitsize, bucket_bitsize; 1169 uint32 regval, max_config_addr, max_addr; 1170 soc_reg_t maxbucket_config_reg, maxbucket_reg; 1171 soc_field_t refresh_f, thd_sel_f, bucket_f; 1172 1173 if (cosq < 0) { 1174 maxbucket_config_reg = CPUPORTMAXBUCKETCONFIG_64r; 1175 maxbucket_reg = CPUPORTMAXBUCKETr; 1176 refresh_f = MAX_REFRESHf; 1177 thd_sel_f = MAX_THD_SELf; 1178 bucket_f = MAX_BUCKETf; 1179 cosq = 0; 1180 } else { 1181 maxbucket_config_reg = CPUMAXBUCKETCONFIG_64r; 1182 maxbucket_reg = CPUMAXBUCKETr; 1183 refresh_f = MAX_REFRESHf; 1184 thd_sel_f = MAX_THDf; 1185 bucket_f = PKT_MAX_BUCKETf; 1186 } 1187 1188 /* 1189 * To set the new Bandwidth settings, the procedure adopted is 1190 * a. reset MAXBUCKETCONFIG and MAXBUCKET 1191 * b. update MAXBUCKETCONFIG with new values passed 1192 * c. if MISCCONFIG.METERING_CLK_EN not set before, enable it. 1193 */ 1194 1195 /* Disable egress metering */ 1196 max_config_addr = soc_reg_addr(unit, maxbucket_config_reg, port, cosq); 1197 BCM_IF_ERROR_RETURN(soc_reg64_read(unit, max_config_addr, ®val_64)); 1198 soc_reg64_field32_set(unit, maxbucket_config_reg, 1199 ®val_64, refresh_f, 0); 1200 soc_reg64_field32_set(unit, maxbucket_config_reg, 1201 ®val_64, thd_sel_f, 0); 1202 BCM_IF_ERROR_RETURN(soc_reg64_write(unit, max_config_addr, regval_64)); 1203 1204 /* reset the MAXBUCKET register*/ 1205 max_addr = soc_reg_addr(unit, maxbucket_reg, port, cosq); 1206 BCM_IF_ERROR_RETURN(soc_reg32_read(unit, max_addr, ®val)); 1207 soc_reg_field_set(unit, maxbucket_reg, ®val, bucket_f, 0); 1208 soc_reg_field_set(unit, maxbucket_reg, ®val, OUT_PROFILE_FLAGf, 0); 1209 BCM_IF_ERROR_RETURN(soc_reg32_write(unit, max_addr, regval)); 1210 1211 meter_flags = flags & BCM_COSQ_BW_PACKET_MODE ? 1212 _BCM_XGS_METER_FLAG_PACKET_MODE : 0; 1213 1214 BCM_IF_ERROR_RETURN(READ_MISCCONFIGr(unit, ®val)); 1215 if (soc_reg_field_get(unit, MISCCONFIGr, regval, ITU_MODE_SELf)) { 1216 meter_flags |= _BCM_XGS_METER_FLAG_NON_LINEAR; 1217 } 1218 meter_flags |= _BCM_XGS_METER_FLAG_GRANULARITY; 1219 1220 refresh_bitsize = 1221 soc_reg_field_length(unit, maxbucket_config_reg, refresh_f); 1222 bucket_bitsize = 1223 soc_reg_field_length(unit, maxbucket_config_reg, thd_sel_f); 1224 1225 BCM_IF_ERROR_RETURN 1226 (_bcm_xgs_kbits_to_bucket_encoding(pps, burst, 1227 meter_flags, refresh_bitsize, bucket_bitsize, 1228 &refresh_rate, &bucketsize, &granularity)); 1229 1230 BCM_IF_ERROR_RETURN(soc_reg64_read(unit, max_config_addr, ®val_64)); 1231 soc_reg64_field32_set(unit, maxbucket_config_reg, 1232 ®val_64, METER_GRANf, granularity); 1233 soc_reg64_field32_set(unit, maxbucket_config_reg, 1234 ®val_64, refresh_f, refresh_rate); 1235 soc_reg64_field32_set(unit, maxbucket_config_reg, 1236 ®val_64, thd_sel_f, bucketsize); 1237 soc_reg64_field32_set(unit, maxbucket_config_reg, ®val_64, MODEf, 1238 (flags & BCM_COSQ_BW_PACKET_MODE) ? 1 : 0); 1239 BCM_IF_ERROR_RETURN(soc_reg64_write(unit, max_config_addr, regval_64)); 1240 1241 /* MISCCONFIG.METERING_CLK_EN is set by chip init */ 1242 1243 return BCM_E_NONE; 1244 } 1245 1246 #endif /* BCM_ENDURO_SUPPORT */ 1247 1248 1249 STATIC int 1250 _bcm_tr_cosq_port_packet_bandwidth_get(int unit, bcm_port_t port, 1251 bcm_cos_queue_t cosq, 1252 int *pps, int *burst) 1253 1254 1255 { 1256 uint32 regval, max_config_addr; 1257 soc_reg_t maxbucket_config_reg; 1258 soc_field_t refresh_f, thd_sel_f; 1259 1260 if (cosq < 0) { 1261 maxbucket_config_reg = CPUPKTPORTMAXBUCKETCONFIGr; 1262 refresh_f = PKT_PORT_MAX_REFRESHf; 1263 thd_sel_f = PKT_PORT_MAX_THD_SELf; 1264 cosq = 0; 1265 } else { 1266 maxbucket_config_reg = CPUPKTMAXBUCKETCONFIGr; 1267 refresh_f = PKT_MAX_REFRESHf; 1268 thd_sel_f = PKT_MAX_THD_SELf; 1269 } 1270 1271 /* Disable egress metering */ 1272 max_config_addr = soc_reg_addr(unit, maxbucket_config_reg, port, cosq); 1273 BCM_IF_ERROR_RETURN(soc_reg32_read(unit, max_config_addr, ®val)); 1274 *pps = soc_reg_field_get(unit, maxbucket_config_reg, regval, refresh_f); 1275 *burst = soc_reg_field_get(unit, maxbucket_config_reg, 1276 regval, thd_sel_f); 1277 1278 return BCM_E_NONE; 1279 } 1280 1281 #ifdef BCM_ENDURO_SUPPORT 1282 1283 STATIC int 1284 _bcm_en_cosq_port_packet_bandwidth_get(int unit, bcm_port_t port, 1285 bcm_cos_queue_t cosq, 1286 int *pps, int *burst, 1287 uint32 *flags) 1288 { 1289 uint64 regval_64; 1290 uint32 refresh_rate = 0, bucketsize = 0, 1291 granularity = 3, meter_flags = 0; 1292 uint32 regval; 1293 uint32 max_config_addr; 1294 1295 soc_reg_t maxbucket_config_reg; 1296 soc_field_t refresh_f, thd_sel_f; 1297 1298 if (cosq < 0) { 1299 maxbucket_config_reg = CPUPORTMAXBUCKETCONFIG_64r; 1300 refresh_f = MAX_REFRESHf; 1301 thd_sel_f = MAX_THD_SELf; 1302 cosq = 0; 1303 } else { 1304 maxbucket_config_reg = CPUMAXBUCKETCONFIG_64r; 1305 refresh_f = MAX_REFRESHf; 1306 thd_sel_f = MAX_THDf; 1307 } 1308 1309 /* Disable egress metering */ 1310 max_config_addr = soc_reg_addr(unit, maxbucket_config_reg, port, cosq); 1311 BCM_IF_ERROR_RETURN(READ_MISCCONFIGr(unit, ®val)); 1312 if (soc_reg_field_get(unit, MISCCONFIGr, regval, ITU_MODE_SELf)) { 1313 meter_flags |= _BCM_XGS_METER_FLAG_NON_LINEAR; 1314 } 1315 1316 *flags = 0; 1317 1318 BCM_IF_ERROR_RETURN(soc_reg64_read(unit, max_config_addr, ®val_64)); 1319 if (soc_reg64_field32_get(unit, maxbucket_config_reg, 1320 regval_64, MODEf)) { 1321 meter_flags |= _BCM_XGS_METER_FLAG_PACKET_MODE; 1322 *flags |= BCM_COSQ_BW_PACKET_MODE; 1323 } 1324 meter_flags |= _BCM_XGS_METER_FLAG_GRANULARITY; 1325 1326 granularity = soc_reg64_field32_get(unit, maxbucket_config_reg, 1327 regval_64, METER_GRANf); 1328 refresh_rate = soc_reg64_field32_get(unit, maxbucket_config_reg, 1329 regval_64, refresh_f); 1330 bucketsize = soc_reg64_field32_get(unit, maxbucket_config_reg, 1331 regval_64, thd_sel_f); 1332 1333 BCM_IF_ERROR_RETURN 1334 (_bcm_xgs_bucket_encoding_to_kbits(refresh_rate, bucketsize, 1335 granularity, meter_flags, 1336 (uint32 *)pps, (uint32 *)burst)); 1337 1338 return BCM_E_NONE; 1339 } 1340 1341 #endif /* BCM_ENDURO_SUPPORT */ 1342 1343 int 1344 bcm_tr_cosq_port_pps_set(int unit, bcm_port_t port, 1345 bcm_cos_queue_t cosq, int pps) 1346 { 1347 int temp_pps, burst; 1348 1349 if (!IS_CPU_PORT(unit, port)) { 1350 return BCM_E_PORT; 1351 } else if (cosq >= NUM_CPU_COSQ(unit)) { 1352 return BCM_E_PARAM; 1353 } else if (pps < 0) { 1354 return BCM_E_PARAM; 1355 } 1356 1357 /* Get the current PPS and BURST settings */ 1358 #ifdef BCM_ENDURO_SUPPORT 1359 if (SOC_IS_ENDURO(unit)) { 1360 uint32 flags; 1361 1362 BCM_IF_ERROR_RETURN 1363 (_bcm_en_cosq_port_packet_bandwidth_get(unit, port, cosq, 1364 &temp_pps, &burst, 1365 &flags)); 1366 1367 /* Replace the current PPS setting, keep BURST the same */ 1368 return _bcm_en_cosq_port_packet_bandwidth_set(unit, port, cosq, 1369 pps, burst, flags | BCM_COSQ_BW_PACKET_MODE); 1370 1371 } else 1372 #endif /* BCM_ENDURO_SUPPORT */ 1373 { 1374 BCM_IF_ERROR_RETURN 1375 (_bcm_tr_cosq_port_packet_bandwidth_get(unit, port, cosq, 1376 &temp_pps, &burst)); 1377 1378 /* Replace the current PPS setting, keep BURST the same */ 1379 return _bcm_tr_cosq_port_packet_bandwidth_set(unit, port, cosq, 1380 pps, burst); 1381 1382 } 1383 } 1384 1385 int 1386 bcm_tr_cosq_port_pps_get(int unit, bcm_port_t port, 1387 bcm_cos_queue_t cosq, int *pps) 1388 { 1389 int burst; 1390 1391 if (!IS_CPU_PORT(unit, port)) { 1392 return BCM_E_PORT; 1393 } else if (cosq >= NUM_CPU_COSQ(unit)) { 1394 return BCM_E_PARAM; 1395 } 1396 1397 #ifdef BCM_ENDURO_SUPPORT 1398 if (SOC_IS_ENDURO(unit)) { 1399 uint32 flags; 1400 1401 return _bcm_en_cosq_port_packet_bandwidth_get(unit, port, cosq, 1402 pps, &burst, &flags); 1403 } else 1404 #endif /* BCM_ENDURO_SUPPORT */ 1405 { 1406 return _bcm_tr_cosq_port_packet_bandwidth_get(unit, port, cosq, 1407 pps, &burst); 1408 } 1409 } 1410 1411 int 1412 bcm_tr_cosq_port_burst_set(int unit, bcm_port_t port, 1413 bcm_cos_queue_t cosq, int burst) 1414 { 1415 int pps, temp_burst; 1416 1417 if (!IS_CPU_PORT(unit, port)) { 1418 return BCM_E_PORT; 1419 } else if (cosq >= NUM_CPU_COSQ(unit)) { 1420 return BCM_E_PARAM; 1421 } else if (burst < 0) { 1422 return BCM_E_PARAM; 1423 } 1424 #ifdef BCM_ENDURO_SUPPORT 1425 if (SOC_IS_ENDURO(unit)) { 1426 uint32 flags; 1427 1428 /* Get the current PPS and BURST settings */ 1429 BCM_IF_ERROR_RETURN 1430 (_bcm_en_cosq_port_packet_bandwidth_get(unit, port, cosq, 1431 &pps, &temp_burst, 1432 &flags)); 1433 1434 /* Replace the current BURST setting, keep PPS the same */ 1435 return _bcm_en_cosq_port_packet_bandwidth_set(unit, port, cosq, 1436 pps, burst, flags | BCM_COSQ_BW_PACKET_MODE); 1437 } else 1438 #endif /* BCM_ENDURO_SUPPORT */ 1439 { 1440 /* Get the current PPS and BURST settings */ 1441 BCM_IF_ERROR_RETURN 1442 (_bcm_tr_cosq_port_packet_bandwidth_get(unit, port, cosq, 1443 &pps, &temp_burst)); 1444 1445 /* Replace the current BURST setting, keep PPS the same */ 1446 return _bcm_tr_cosq_port_packet_bandwidth_set(unit, port, cosq, 1447 pps, burst); 1448 } 1449 } 1450 1451 int 1452 bcm_tr_cosq_port_burst_get(int unit, bcm_port_t port, 1453 bcm_cos_queue_t cosq, int *burst) 1454 { 1455 int pps; 1456 1457 if (!IS_CPU_PORT(unit, port)) { 1458 return BCM_E_PORT; 1459 } else if (cosq >= NUM_CPU_COSQ(unit)) { 1460 return BCM_E_PARAM; 1461 } 1462 1463 #ifdef BCM_ENDURO_SUPPORT 1464 if (SOC_IS_ENDURO(unit)) { 1465 uint32 flags; 1466 1467 return _bcm_en_cosq_port_packet_bandwidth_get(unit, port, cosq, 1468 &pps, burst, &flags); 1469 } else 1470 #endif /* BCM_ENDURO_SUPPORT */ 1471 { 1472 return _bcm_tr_cosq_port_packet_bandwidth_get(unit, port, cosq, 1473 &pps, burst); 1474 } 1475 } 1476 1477 int 1478 _bcm_tr_cosq_port_resolve(int unit, bcm_gport_t gport, 1479 bcm_module_t *modid, bcm_port_t *port, 1480 bcm_trunk_t *trunk_id, int *id) 1481 { 1482 bcm_module_t mod_in; 1483 bcm_port_t port_in; 1484 1485 if (BCM_GPORT_IS_SCHEDULER(gport)) { 1486 mod_in = (BCM_GPORT_SCHEDULER_GET(gport) >> 8) & 0xff; 1487 port_in = BCM_GPORT_SCHEDULER_GET(gport) & 0xff; 1488 *id = BCM_GPORT_SCHEDULER_GET(gport); 1489 *trunk_id = -1; 1490 1491 /* Since the modid/port in the scheduler GPORT is the 1492 * applications modid/port space, convert to local space. 1493 */ 1494 BCM_IF_ERROR_RETURN 1495 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET, 1496 mod_in, port_in, modid, port)); 1497 1498 if (!_tr_num_port_cosq[unit]) { 1499 return BCM_E_INIT; 1500 } else if (!SOC_PBMP_MEMBER(_tr_cosq_24q_ports[unit], *port)) { 1501 return BCM_E_BADID; 1502 } else if (_tr_num_port_cosq[unit][*port] == 0) { 1503 return BCM_E_NOT_FOUND; 1504 } 1505 } else { 1506 return BCM_E_BADID; 1507 } 1508 return BCM_E_NONE; 1509 } 1510 1511 STATIC int 1512 _bcm_tr_cosq_resolve_mod_port(int unit, bcm_gport_t gport, 1513 bcm_module_t *modid, bcm_port_t *port, 1514 bcm_trunk_t *trunk_id) 1515 { 1516 int gport_id, result; 1517 1518 BCM_IF_ERROR_RETURN 1519 (_bcm_esw_gport_resolve(unit, gport, modid, 1520 port, trunk_id, &gport_id)); 1521 BCM_IF_ERROR_RETURN( 1522 _bcm_esw_modid_is_local(unit, *modid, &result)); 1523 1524 if (TRUE != result) { 1525 return BCM_E_PORT; 1526 } 1527 return BCM_E_NONE; 1528 } 1529 1530 STATIC int 1531 _bcm_tr_cosq_discard_cap_enable_set(int unit, bcm_port_t port, 1532 bcm_cos_queue_t cosq, soc_reg_t config_reg, 1533 uint32 flags) 1534 { 1535 uint32 val, addr; 1536 1537 addr = soc_reg_addr(unit, config_reg, port, cosq); 1538 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &val)); 1539 1540 if (flags & BCM_COSQ_DISCARD_CAP_AVERAGE) { 1541 soc_reg_field_set(unit, config_reg, &val, CAP_AVERAGEf, 1); 1542 } else { 1543 soc_reg_field_set(unit, config_reg, &val, CAP_AVERAGEf, 0); 1544 } 1545 if (flags & BCM_COSQ_DISCARD_ENABLE) { 1546 soc_reg_field_set(unit, config_reg, &val, ENABLEf, 1); 1547 } else { 1548 soc_reg_field_set(unit, config_reg, &val, ENABLEf, 0); 1549 } 1550 SOC_IF_ERROR_RETURN(soc_reg32_write(unit, addr, val)); 1551 return BCM_E_NONE; 1552 } 1553 1554 STATIC int 1555 _bcm_tr_cosq_discard_cap_enable_get(int unit, bcm_port_t port, 1556 bcm_cos_queue_t cosq, soc_reg_t config_reg, 1557 uint32 *flags) 1558 { 1559 uint32 val, addr; 1560 1561 addr = soc_reg_addr(unit, config_reg, port, cosq); 1562 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &val)); 1563 1564 if (soc_reg_field_get(unit, config_reg, val, CAP_AVERAGEf)) { 1565 *flags |= BCM_COSQ_DISCARD_CAP_AVERAGE; 1566 } 1567 if (soc_reg_field_get(unit, config_reg, val, ENABLEf)) { 1568 *flags |= BCM_COSQ_DISCARD_ENABLE; 1569 } 1570 return BCM_E_NONE; 1571 } 1572 1573 int 1574 bcm_tr_cosq_discard_set(int unit, uint32 flags) 1575 { 1576 bcm_port_t port; 1577 bcm_cos_queue_t cosq; 1578 soc_reg_t config_reg = WREDCONFIG_PACKETr; 1579 1580 if (flags & ~(BCM_COSQ_DISCARD_CAP_AVERAGE | 1581 BCM_COSQ_DISCARD_ENABLE)) { 1582 return BCM_E_PARAM; 1583 } 1584 1585 PBMP_ALL_ITER(unit, port) { 1586 if (IS_CPU_PORT(unit, port)) { 1587 continue; 1588 } 1589 for (cosq = 0; cosq < 8; cosq++) { 1590 BCM_IF_ERROR_RETURN 1591 (_bcm_tr_cosq_discard_cap_enable_set(unit, port, cosq, 1592 config_reg, flags)); 1593 } 1594 if (SOC_PBMP_MEMBER(_tr_cosq_24q_ports[unit], port)) { 1595 for (cosq = 8; cosq < 24; cosq++) { 1596 BCM_IF_ERROR_RETURN 1597 (_bcm_tr_cosq_discard_cap_enable_set(unit, port, cosq, 1598 config_reg, flags)); 1599 } 1600 } 1601 } 1602 return BCM_E_NONE; 1603 } 1604 1605 int 1606 bcm_tr_cosq_discard_get(int unit, uint32 *flags) 1607 { 1608 int rv = BCM_E_NONE; 1609 bcm_port_t port; 1610 soc_reg_t config_reg = WREDCONFIG_PACKETr; 1611 1612 PBMP_ALL_ITER(unit, port) { 1613 if (IS_CPU_PORT(unit, port)) { 1614 continue; 1615 } 1616 *flags = 0; 1617 rv = _bcm_tr_cosq_discard_cap_enable_get(unit, port, 0, 1618 config_reg, flags); 1619 break; 1620 } 1621 return rv; 1622 } 1623 1624 /* 1625 * Convert HW drop probability to percent value 1626 */ 1627 STATIC int 1628 _bcm_tr_hw_drop_prob_to_percent[] = { 1629 0, /* 0 */ 1630 1, /* 1 */ 1631 2, /* 2 */ 1632 3, /* 3 */ 1633 4, /* 4 */ 1634 5, /* 5 */ 1635 6, /* 6 */ 1636 7, /* 7 */ 1637 8, /* 8 */ 1638 9, /* 9 */ 1639 10, /* 10 */ 1640 25, /* 11 */ 1641 50, /* 12 */ 1642 75, /* 13 */ 1643 100, /* 14 */ 1644 -1 /* 15 */ 1645 }; 1646 1647 STATIC int 1648 _bcm_tr_percent_to_drop_prob(int percent) { 1649 int i; 1650 1651 for (i=14; i > 0 ; i--) { 1652 if (percent >= _bcm_tr_hw_drop_prob_to_percent[i]) { 1653 break; 1654 } 1655 } 1656 return i; 1657 } 1658 1659 STATIC int 1660 _bcm_tr_drop_prob_to_percent(int drop_prob) { 1661 return (_bcm_tr_hw_drop_prob_to_percent[drop_prob]); 1662 } 1663 1664 STATIC int 1665 _bcm_tr_angle_to_packets_table[] = 1666 { 1667 /* 0.. 5 */ 16383, 5727, 2862, 1908, 1430, 1142, 1668 /* 6..11 */ 951, 814, 711, 631, 567, 514, 1669 /* 12..17 */ 470, 433, 401, 373, 348, 327, 1670 /* 18..23 */ 307, 290, 274, 260, 247, 235, 1671 /* 24..29 */ 224, 214, 205, 196, 188, 180, 1672 /* 30..35 */ 173, 166, 160, 153, 148, 142, 1673 /* 36..41 */ 137, 132, 127, 123, 119, 115, 1674 /* 42..47 */ 111, 107, 103, 100, 96, 93, 1675 /* 48..53 */ 90, 86, 83, 80, 78, 75, 1676 /* 54..59 */ 72, 70, 67, 64, 62, 60, 1677 /* 60..65 */ 57, 55, 53, 50, 48, 46, 1678 /* 66..71 */ 44, 42, 40, 38, 36, 34, 1679 /* 72..77 */ 32, 30, 28, 26, 24, 23, 1680 /* 78..83 */ 21, 19, 17, 15, 14, 12, 1681 /* 84..89 */ 10, 8, 6, 5, 3, 1, 1682 /* 90 */ 0 1683 }; 1684 1685 /* 1686 * Given a slope (angle in degrees) from 0 to 90, return 1687 * the number of packets in the range from 0% drop 1688 * probability to 100% drop probability. 1689 */ 1690 STATIC int 1691 _bcm_tr_angle_to_packets(int angle) { 1692 return (_bcm_tr_angle_to_packets_table[angle]); 1693 } 1694 1695 /* 1696 * Given a number of packets in the range from 0% drop probability 1697 * to 100% drop probability, return the slope (angle in degrees). 1698 */ 1699 STATIC int 1700 _bcm_tr_packets_to_angle(int packets) { 1701 int angle; 1702 1703 for (angle = 90; angle >= 0 ; angle--) { 1704 if (packets <= _bcm_tr_angle_to_packets_table[angle]) { 1705 break; 1706 } 1707 } 1708 return angle; 1709 } 1710 1711 STATIC int 1712 _bcm_tr_cosq_discard_set(int unit, bcm_port_t port, uint32 flags, 1713 bcm_cos_queue_t cosq, soc_reg_t config_reg, 1714 soc_reg_t thresh_reg_green, 1715 soc_reg_t thresh_reg_yellow, 1716 soc_reg_t thresh_reg_red, 1717 soc_reg_t thresh_reg_non_tcp, 1718 uint32 min_thresh, uint32 max_thresh, 1719 int drop_probability, int gain) 1720 { 1721 uint32 val, addr; 1722 1723 if (flags & ~(BCM_COSQ_DISCARD_COLOR_GREEN | 1724 BCM_COSQ_DISCARD_COLOR_YELLOW | 1725 BCM_COSQ_DISCARD_COLOR_RED | 1726 BCM_COSQ_DISCARD_COLOR_ALL | 1727 BCM_COSQ_DISCARD_CAP_AVERAGE | 1728 BCM_COSQ_DISCARD_PACKETS | 1729 BCM_COSQ_DISCARD_BYTES | 1730 BCM_COSQ_DISCARD_ENABLE | 1731 BCM_COSQ_DISCARD_NONTCP)) { 1732 return BCM_E_PARAM; 1733 } 1734 1735 addr = soc_reg_addr(unit, config_reg, port, cosq); 1736 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &val)); 1737 1738 /* Program the weight */ 1739 soc_reg_field_set(unit, config_reg, &val, WEIGHTf, gain); 1740 1741 /* Program the drop probabilty */ 1742 if ((flags & BCM_COSQ_DISCARD_COLOR_GREEN) || 1743 ((flags & BCM_COSQ_DISCARD_COLOR_ALL) == BCM_COSQ_DISCARD_COLOR_ALL)) { 1744 soc_reg_field_set(unit, config_reg, &val, MAXDROPRATEf, 1745 _bcm_tr_percent_to_drop_prob(drop_probability)); 1746 } 1747 if ((flags & BCM_COSQ_DISCARD_COLOR_YELLOW) || 1748 ((flags & BCM_COSQ_DISCARD_COLOR_ALL) == BCM_COSQ_DISCARD_COLOR_ALL)) { 1749 soc_reg_field_set(unit, config_reg, &val, YELLOW_MAXDROPRATEf, 1750 _bcm_tr_percent_to_drop_prob(drop_probability)); 1751 } 1752 if ((flags & BCM_COSQ_DISCARD_COLOR_RED) || 1753 ((flags & BCM_COSQ_DISCARD_COLOR_ALL) == BCM_COSQ_DISCARD_COLOR_ALL)) { 1754 soc_reg_field_set(unit, config_reg, &val, RED_MAXDROPRATEf, 1755 _bcm_tr_percent_to_drop_prob(drop_probability)); 1756 } 1757 if (flags & BCM_COSQ_DISCARD_NONTCP) { 1758 soc_reg_field_set(unit, config_reg, &val, NONTCP_MAXDROPRATEf, 1759 _bcm_tr_percent_to_drop_prob(drop_probability)); 1760 } 1761 SOC_IF_ERROR_RETURN(soc_reg32_write(unit, addr, val)); 1762 1763 /* Program the min and max thresholds */ 1764 if ((flags & BCM_COSQ_DISCARD_COLOR_GREEN) || 1765 ((flags & BCM_COSQ_DISCARD_COLOR_ALL) == BCM_COSQ_DISCARD_COLOR_ALL)) { 1766 addr = soc_reg_addr(unit, thresh_reg_green, port, cosq); 1767 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &val)); 1768 soc_reg_field_set(unit, thresh_reg_green, &val, DROPSTARTPOINTf, 1769 min_thresh); 1770 soc_reg_field_set(unit, thresh_reg_green, &val, DROPENDPOINTf, 1771 max_thresh); 1772 SOC_IF_ERROR_RETURN(soc_reg32_write(unit, addr, val)); 1773 } 1774 if ((flags & BCM_COSQ_DISCARD_COLOR_YELLOW) || 1775 ((flags & BCM_COSQ_DISCARD_COLOR_ALL) == BCM_COSQ_DISCARD_COLOR_ALL)) { 1776 addr = soc_reg_addr(unit, thresh_reg_yellow, port, cosq); 1777 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &val)); 1778 soc_reg_field_set(unit, thresh_reg_yellow, &val, 1779 YELLOW_DROPSTARTPOINTf, min_thresh); 1780 soc_reg_field_set(unit, thresh_reg_yellow, &val, 1781 YELLOW_DROPENDPOINTf, max_thresh); 1782 SOC_IF_ERROR_RETURN(soc_reg32_write(unit, addr, val)); 1783 } 1784 if ((flags & BCM_COSQ_DISCARD_COLOR_RED) || 1785 ((flags & BCM_COSQ_DISCARD_COLOR_ALL) == BCM_COSQ_DISCARD_COLOR_ALL)) { 1786 addr = soc_reg_addr(unit, thresh_reg_red, port, cosq); 1787 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &val)); 1788 soc_reg_field_set(unit, thresh_reg_red, &val, 1789 RED_DROPSTARTPOINTf, min_thresh); 1790 soc_reg_field_set(unit, thresh_reg_red, &val, 1791 RED_DROPENDPOINTf, max_thresh); 1792 SOC_IF_ERROR_RETURN(soc_reg32_write(unit, addr, val)); 1793 } 1794 if (flags & BCM_COSQ_DISCARD_NONTCP) { 1795 addr = soc_reg_addr(unit, thresh_reg_non_tcp, port, cosq); 1796 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &val)); 1797 soc_reg_field_set(unit, thresh_reg_non_tcp, &val, 1798 NONTCP_DROPSTARTPOINTf, min_thresh); 1799 soc_reg_field_set(unit, thresh_reg_non_tcp, &val, 1800 NONTCP_DROPENDPOINTf, max_thresh); 1801 SOC_IF_ERROR_RETURN(soc_reg32_write(unit, addr, val)); 1802 } 1803 return BCM_E_NONE; 1804 } 1805 1806 STATIC int 1807 _bcm_tr_cosq_discard_get(int unit, bcm_port_t port, uint32 flags, 1808 bcm_cos_queue_t cosq, soc_reg_t config_reg, 1809 soc_reg_t thresh_reg_green, 1810 soc_reg_t thresh_reg_yellow, 1811 soc_reg_t thresh_reg_red, 1812 soc_reg_t thresh_reg_non_tcp, 1813 uint32 *min_thresh, uint32 *max_thresh, 1814 int *drop_probability, int *gain) 1815 { 1816 uint32 val, addr, drop_rate; 1817 1818 addr = soc_reg_addr(unit, config_reg, port, cosq); 1819 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &val)); 1820 1821 /* Get the weight */ 1822 *gain = soc_reg_field_get(unit, config_reg, val, WEIGHTf); 1823 1824 /* Get the drop probabilty */ 1825 if (flags & BCM_COSQ_DISCARD_COLOR_YELLOW) { 1826 drop_rate = soc_reg_field_get(unit, config_reg, val, 1827 YELLOW_MAXDROPRATEf); 1828 } else if (flags & BCM_COSQ_DISCARD_COLOR_RED) { 1829 drop_rate = soc_reg_field_get(unit, config_reg, val, 1830 RED_MAXDROPRATEf); 1831 } else { 1832 drop_rate = soc_reg_field_get(unit, config_reg, val, 1833 MAXDROPRATEf); 1834 } 1835 *drop_probability = _bcm_tr_drop_prob_to_percent(drop_rate); 1836 1837 /* Get the min and max thresholds */ 1838 if (flags & BCM_COSQ_DISCARD_COLOR_YELLOW) { 1839 addr = soc_reg_addr(unit, thresh_reg_yellow, port, cosq); 1840 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &val)); 1841 *min_thresh = soc_reg_field_get(unit, thresh_reg_yellow, val, 1842 YELLOW_DROPSTARTPOINTf); 1843 *max_thresh = soc_reg_field_get(unit, thresh_reg_yellow, val, 1844 YELLOW_DROPENDPOINTf); 1845 } else if (flags & BCM_COSQ_DISCARD_COLOR_RED) { 1846 addr = soc_reg_addr(unit, thresh_reg_red, port, cosq); 1847 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &val)); 1848 *min_thresh = soc_reg_field_get(unit, thresh_reg_red, val, 1849 RED_DROPSTARTPOINTf); 1850 *max_thresh = soc_reg_field_get(unit, thresh_reg_red, val, 1851 RED_DROPENDPOINTf); 1852 } else { 1853 addr = soc_reg_addr(unit, thresh_reg_green, port, cosq); 1854 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &val)); 1855 *min_thresh = soc_reg_field_get(unit, thresh_reg_green, val, 1856 DROPSTARTPOINTf); 1857 *max_thresh = soc_reg_field_get(unit, thresh_reg_green, val, 1858 DROPENDPOINTf); 1859 } 1860 return BCM_E_NONE; 1861 } 1862 1863 #define ABS(n) (((n) < 0) ? -(n) : (n)) 1864 1865 int 1866 bcm_tr_cosq_discard_port_set(int unit, bcm_port_t port, 1867 bcm_cos_queue_t cosq, 1868 uint32 color, 1869 int drop_start, 1870 int drop_slope, 1871 int average_time) 1872 { 1873 bcm_module_t modid; 1874 bcm_port_t local_port; 1875 bcm_trunk_t trunk_id; 1876 bcm_pbmp_t pbmp; 1877 int i, gain, cosq_start, num_cosq; 1878 uint32 min_thresh, max_thresh, shared_limit; 1879 uint32 rval, bits; 1880 1881 if (!_tr_num_port_cosq[unit]) { 1882 return BCM_E_INIT; 1883 } 1884 1885 if (drop_start < 0 || drop_start > 100 || 1886 drop_slope < 0 || drop_slope > 90) { 1887 return BCM_E_PARAM; 1888 } 1889 1890 if (BCM_GPORT_IS_SET(port)) { 1891 if (BCM_GPORT_IS_SCHEDULER(port)) { 1892 BCM_IF_ERROR_RETURN 1893 (_bcm_tr_cosq_resolve_mod_port(unit, port, &modid, 1894 &local_port, &trunk_id)); 1895 } else { 1896 BCM_IF_ERROR_RETURN 1897 (bcm_esw_port_local_get(unit, port, &local_port)); 1898 } 1899 BCM_PBMP_PORT_SET(pbmp, local_port); 1900 } else { 1901 if (port == -1) { 1902 BCM_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit)); 1903 } else if (IS_CPU_PORT(unit, port) || !SOC_PORT_VALID(unit, port)) { 1904 return BCM_E_PORT; 1905 } else { 1906 BCM_PBMP_PORT_SET(pbmp, port); 1907 local_port = port; 1908 } 1909 } 1910 1911 if (BCM_GPORT_IS_SCHEDULER(port)) { 1912 if (_tr_num_port_cosq[unit][local_port] == 0) { 1913 return BCM_E_NOT_FOUND; 1914 } else if (cosq < -1 || cosq >= _tr_num_port_cosq[unit][local_port]) { 1915 return BCM_E_PARAM; 1916 } else if (cosq == -1) { 1917 cosq_start = 8; 1918 num_cosq = _tr_num_port_cosq[unit][local_port]; 1919 } else { 1920 cosq_start = cosq + 8; 1921 num_cosq = 1; 1922 } 1923 } else { 1924 if (cosq < -1 || cosq >= _tr_num_cosq[unit]) { 1925 return BCM_E_PARAM; 1926 } else if (cosq == -1) { 1927 cosq_start = 0; 1928 num_cosq = 8; 1929 } else { 1930 cosq_start = cosq; 1931 num_cosq = 1; 1932 } 1933 } 1934 1935 /* 1936 * average queue size is reculated every 4us, the formula is 1937 * avg_qsize(t + 1) = 1938 * avg_qsize(t) + (cur_qsize - avg_qsize(t)) / (2 ** gain) 1939 * gain = log2(average_time / 4) 1940 */ 1941 bits = (average_time / 4) & 0xffff; 1942 bits |= bits >> 1; 1943 bits |= bits >> 2; 1944 bits |= bits >> 4; 1945 bits |= bits >> 8; 1946 gain = _shr_popcount(bits); 1947 /* Don't allow negative value of gain */ 1948 if (gain) { 1949 gain -= 1; 1950 } 1951 1952 /* 1953 * per-port packet limit may be disabled. 1954 * per-port per-cos packet limit may be set to use dynamic method. 1955 * therefore drop_start percentage is based on per-device total shared 1956 * packets. 1957 */ 1958 SOC_IF_ERROR_RETURN(READ_OP_BUFFER_SHARED_LIMIT_PACKETr(unit, &rval)); 1959 shared_limit = soc_reg_field_get(unit, OP_BUFFER_SHARED_LIMIT_PACKETr, 1960 rval, OP_BUFFER_SHARED_LIMIT_PACKETf); 1961 min_thresh = drop_start * shared_limit / 100; 1962 1963 /* Calculate the max threshold. For a given slope (angle in 1964 * degrees), determine how many packets are in the range from 1965 * 0% drop probability to 100% drop probability. Add that 1966 * number to the min_treshold to the the max_threshold. 1967 */ 1968 max_thresh = min_thresh + _bcm_tr_angle_to_packets(drop_slope); 1969 if (max_thresh > TR_PACKET_FIELD_MAX(unit)) { 1970 max_thresh = TR_PACKET_FIELD_MAX(unit); 1971 } 1972 1973 BCM_PBMP_ITER(pbmp, local_port) { 1974 for (i = cosq_start; i < (cosq_start + num_cosq); i++) { 1975 BCM_IF_ERROR_RETURN 1976 (_bcm_tr_cosq_discard_set(unit, local_port, color, i, 1977 WREDCONFIG_PACKETr, 1978 WREDPARAM_PACKETr, 1979 WREDPARAM_YELLOW_PACKETr, 1980 WREDPARAM_RED_PACKETr, 1981 WREDPARAM_NONTCP_PACKETr, 1982 min_thresh, max_thresh, 100, gain)); 1983 } 1984 } 1985 return BCM_E_NONE; 1986 } 1987 1988 int 1989 bcm_tr_cosq_discard_port_get(int unit, bcm_port_t port, 1990 bcm_cos_queue_t cosq, 1991 uint32 color, 1992 int *drop_start, 1993 int *drop_slope, 1994 int *average_time) 1995 { 1996 bcm_module_t modid; 1997 bcm_port_t local_port; 1998 bcm_trunk_t trunk_id; 1999 bcm_pbmp_t pbmp; 2000 int gain, drop_prob; 2001 uint32 min_thresh, max_thresh, shared_limit; 2002 uint32 rval; 2003 2004 if (!_tr_num_port_cosq[unit]) { 2005 return BCM_E_INIT; 2006 } 2007 2008 if (drop_start == NULL || drop_slope == NULL || average_time == NULL) { 2009 return BCM_E_PARAM; 2010 } 2011 2012 if (BCM_GPORT_IS_SET(port)) { 2013 if (BCM_GPORT_IS_SCHEDULER(port)) { 2014 BCM_IF_ERROR_RETURN 2015 (_bcm_tr_cosq_resolve_mod_port(unit, port, &modid, 2016 &local_port, &trunk_id)); 2017 } else { 2018 BCM_IF_ERROR_RETURN 2019 (bcm_esw_port_local_get(unit, port, &local_port)); 2020 } 2021 BCM_PBMP_PORT_SET(pbmp, local_port); 2022 } else { 2023 if (port == -1) { 2024 #ifdef BCM_ENDURO_SUPPORT 2025 if (SOC_IS_ENDURO(unit)) { 2026 BCM_PBMP_ASSIGN(pbmp, PBMP_E_ALL(unit)); 2027 } else 2028 #endif /* BCM_ENDURO_SUPPORT */ 2029 { 2030 BCM_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit)); 2031 } 2032 } else if (IS_CPU_PORT(unit, port) || !SOC_PORT_VALID(unit, port)) { 2033 return BCM_E_PORT; 2034 } else { 2035 BCM_PBMP_PORT_SET(pbmp, port); 2036 local_port = port; 2037 } 2038 } 2039 2040 if (BCM_GPORT_IS_SCHEDULER(port)) { 2041 if (_tr_num_port_cosq[unit][local_port] == 0) { 2042 return BCM_E_NOT_FOUND; 2043 } else if (cosq < -1 || cosq >= _tr_num_port_cosq[unit][local_port]) { 2044 return BCM_E_PARAM; 2045 } else if (cosq == -1) { 2046 cosq = 8; 2047 } else { 2048 cosq = cosq + 8; 2049 } 2050 } else { 2051 if (cosq < -1 || cosq >= _tr_num_cosq[unit]) { 2052 return BCM_E_PARAM; 2053 } else if (cosq == -1) { 2054 cosq = 0; 2055 } 2056 } 2057 2058 BCM_PBMP_ITER(pbmp, local_port) { 2059 BCM_IF_ERROR_RETURN 2060 (_bcm_tr_cosq_discard_get(unit, local_port, color, cosq, 2061 WREDCONFIG_PACKETr, 2062 WREDPARAM_PACKETr, 2063 WREDPARAM_YELLOW_PACKETr, 2064 WREDPARAM_RED_PACKETr, 2065 WREDPARAM_NONTCP_PACKETr, 2066 &min_thresh, &max_thresh, &drop_prob, 2067 &gain)); 2068 2069 /* 2070 * average queue size is reculated every 4us, the formula is 2071 * avg_qsize(t + 1) = 2072 * avg_qsize(t) + (cur_qsize - avg_qsize(t)) / (2 ** gain) 2073 */ 2074 *average_time = (1 << gain) * 4; 2075 2076 /* 2077 * per-port packet limit may be disabled. 2078 * per-port per-cos packet limit may be set to use dynamic method. 2079 * therefore drop_start percentage is based on per-device total shared 2080 * packets. 2081 */ 2082 SOC_IF_ERROR_RETURN(READ_OP_BUFFER_SHARED_LIMIT_PACKETr(unit, &rval)); 2083 shared_limit = soc_reg_field_get(unit, OP_BUFFER_SHARED_LIMIT_PACKETr, 2084 rval, OP_BUFFER_SHARED_LIMIT_PACKETf); 2085 if (min_thresh >= shared_limit) { 2086 *drop_start = 100; 2087 } else { 2088 *drop_start = min_thresh * 100 / shared_limit; 2089 } 2090 2091 /* Calculate the slope using the min and max threshold. 2092 * The angle is calculated knowing drop probability at min 2093 * threshold is 0% and drop probability at max threshold is 100%. 2094 */ 2095 *drop_slope = _bcm_tr_packets_to_angle(max_thresh - min_thresh); 2096 break; 2097 } 2098 2099 return BCM_E_NONE; 2100 } 2101 2102 STATIC int 2103 _bcm_tr_cosq_port_sched_set(int unit, soc_reg_t config_reg, 2104 soc_reg_t weight_reg, soc_reg_t minsp_reg, 2105 bcm_port_t port, bcm_cos_queue_t start_cosq, 2106 int num_weights, const int weights[], 2107 int mode) 2108 { 2109 int t, i; 2110 uint32 cfg_addr, cosw_addr, minsp_addr, cfg, cosw, minsp; 2111 int mbits = 0; 2112 int weight_max, sel, quanta; 2113 2114 cfg_addr = soc_reg_addr(unit, config_reg, port, 0); 2115 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, cfg_addr, &cfg)); 2116 2117 switch (mode) { 2118 case BCM_COSQ_STRICT: 2119 mbits = 0; 2120 break; 2121 case BCM_COSQ_ROUND_ROBIN: 2122 mbits = 1; 2123 break; 2124 case BCM_COSQ_WEIGHTED_ROUND_ROBIN: 2125 mbits = 2; 2126 /* 2127 * All weight values must fit within 7 bits. 2128 * If weight is 0, this queue is run in strict mode, 2129 * others run in WRR mode. 2130 */ 2131 for(i = 0; i < num_weights; i++) { 2132 if (weights[i] > TR_WRR_WEIGHT_MAX) { 2133 return BCM_E_PARAM; 2134 } 2135 } 2136 for (i = 0; i < num_weights; i++) { 2137 cosw_addr = soc_reg_addr(unit, weight_reg, port, start_cosq + i); 2138 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, cosw_addr, &cosw)); 2139 soc_reg_field_set(unit, weight_reg, &cosw, COSWEIGHTSf, 2140 weights[i]); 2141 SOC_IF_ERROR_RETURN(soc_reg32_write(unit, cosw_addr, cosw)); 2142 } 2143 break; 2144 case BCM_COSQ_DEFICIT_ROUND_ROBIN: 2145 mbits = 3; 2146 2147 weight_max = 0; 2148 for (i = 0; i < num_weights; i++) { 2149 if (weight_max < weights[i]) { 2150 weight_max = weights[i]; 2151 } 2152 } 2153 2154 for (sel = 0; sel <= 3; sel++) { 2155 if (weight_max <= TR_DRR_WEIGHT_MAX * (1 << (sel + 1))) { 2156 break; 2157 } 2158 } 2159 if (sel > 3) { 2160 return BCM_E_PARAM; 2161 } 2162 quanta = 1 << (sel + 1); 2163 soc_reg_field_set(unit, config_reg, &cfg, MTU_QUANTA_SELECTf, sel); 2164 for (i = 0; i < num_weights; i++) { 2165 cosw_addr = soc_reg_addr(unit, weight_reg, port, start_cosq + i); 2166 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, cosw_addr, &cosw)); 2167 /* the unit of weight for WDRR is specified mtu quanta */ 2168 soc_reg_field_set(unit, weight_reg, &cosw, COSWEIGHTSf, 2169 (weights[i] + quanta - 1) / quanta); 2170 SOC_IF_ERROR_RETURN(soc_reg32_write(unit, cosw_addr, cosw)); 2171 } 2172 break; 2173 case BCM_COSQ_BOUNDED_DELAY: /* not supported in xgs */ 2174 default: 2175 return BCM_E_PARAM; 2176 } 2177 2178 if ((mode == BCM_COSQ_WEIGHTED_ROUND_ROBIN) || 2179 (mode == BCM_COSQ_DEFICIT_ROUND_ROBIN)) { 2180 /* Set strict priority bit if weight is zero */ 2181 minsp_addr = soc_reg_addr(unit, minsp_reg, port, 0); 2182 SOC_IF_ERROR_RETURN 2183 (soc_reg32_read(unit, minsp_addr, &minsp)); 2184 for(i = 0; i < num_weights; i++) { 2185 t = start_cosq + i; 2186 if (weights[i] == 0) { 2187 minsp |= (1 << t); 2188 } else { 2189 minsp &= ~(1 << t); 2190 } 2191 } 2192 SOC_IF_ERROR_RETURN 2193 (soc_reg32_write(unit, minsp_addr, minsp)); 2194 } 2195 2196 /* Program the scheduling mode */ 2197 soc_reg_field_set(unit, config_reg, &cfg, SCHEDULING_SELECTf, mbits); 2198 SOC_IF_ERROR_RETURN(soc_reg32_write(unit, cfg_addr, cfg)); 2199 2200 return BCM_E_NONE; 2201 } 2202 2203 STATIC int 2204 _bcm_tr_cosq_port_sched_get(int unit, soc_reg_t config_reg, 2205 soc_reg_t weight_reg, bcm_port_t port, 2206 bcm_cos_queue_t start_cosq, 2207 int num_weights, int weights[], int *mode) 2208 { 2209 uint32 addr, cfg, cosw; 2210 int mbits, i; 2211 uint32 quanta; 2212 2213 addr = soc_reg_addr(unit, config_reg, port, 0); 2214 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &cfg)); 2215 mbits = soc_reg_field_get(unit, config_reg, cfg, SCHEDULING_SELECTf); 2216 2217 switch (mbits) { 2218 case 0: 2219 *mode = BCM_COSQ_STRICT; 2220 break; 2221 case 1: 2222 *mode = BCM_COSQ_ROUND_ROBIN; 2223 break; 2224 case 2: 2225 *mode = BCM_COSQ_WEIGHTED_ROUND_ROBIN; 2226 for (i = 0; i < num_weights; i++) { 2227 addr = soc_reg_addr(unit, weight_reg, port, start_cosq + i); 2228 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &cosw)); 2229 weights[i] = soc_reg_field_get(unit, weight_reg, cosw, 2230 COSWEIGHTSf); 2231 } 2232 break; 2233 case 3: 2234 *mode = BCM_COSQ_DEFICIT_ROUND_ROBIN; 2235 switch (soc_reg_field_get(unit, config_reg, cfg, MTU_QUANTA_SELECTf)) { 2236 case 0: /* quanta is 2k bytes */ 2237 quanta = 2; 2238 break; 2239 case 1: /* quanta is 4k bytes */ 2240 quanta = 4; 2241 break; 2242 case 2: /* quanta is 8k bytes */ 2243 quanta = 8; 2244 break; 2245 case 3: /* quanta is 16k bytes */ 2246 quanta = 16; 2247 break; 2248 default: 2249 return SOC_E_INTERNAL; 2250 } 2251 for (i = 0; i < num_weights; i++) { 2252 addr = soc_reg_addr(unit, weight_reg, port, start_cosq + i); 2253 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &cosw)); 2254 /* the unit of weight for WDRR is specified mtu quanta */ 2255 weights[i] = soc_reg_field_get(unit, weight_reg, cosw, 2256 COSWEIGHTSf) * quanta; 2257 } 2258 break; 2259 default: 2260 return BCM_E_INTERNAL; 2261 } 2262 2263 return BCM_E_NONE; 2264 } 2265 2266 /* 2267 * Function: 2268 * bcm_cosq_port_sched_set 2269 * Purpose: 2270 * Set up class-of-service policy and corresponding weights and delay 2271 * Parameters: 2272 * unit - StrataSwitch unit number. 2273 * pbm - port bitmap 2274 * mode - Scheduling mode, one of BCM_COSQ_xxx 2275 * weights - Weights for each COS queue 2276 * Only for BCM_COSQ_WEIGHTED_FAIR_ROUND_ROBIN mode. 2277 * For DRR Weight is specified in Kbytes 2278 * delay - This parameter is not used 2279 * Returns: 2280 * BCM_E_XXX 2281 */ 2282 2283 int 2284 bcm_tr_cosq_port_sched_set(int unit, bcm_pbmp_t pbm, 2285 int mode, const int weights[], int delay) 2286 { 2287 bcm_port_t port; 2288 uint32 rval, mbits; 2289 int i,max_weight; 2290 2291 mbcm_driver[unit]->mbcm_cosq_sched_weight_max_get(unit, mode, &max_weight); 2292 if((mode != BCM_COSQ_STRICT) && (mode != BCM_COSQ_ROUND_ROBIN) && 2293 (max_weight != BCM_COSQ_WEIGHT_UNLIMITED)) { 2294 for(i = 0; i < NUM_COS(unit); i++) { 2295 if((weights[i] < 0) || (weights[i] > max_weight)) { 2296 return BCM_E_PARAM; 2297 } 2298 } 2299 } 2300 2301 PBMP_ITER(pbm, port) { 2302 /* coverity[overrun-local : FALSE] */ 2303 if (IS_CPU_PORT(unit, port) && !SOC_IS_ENDURO(unit)) { 2304 switch (mode) { 2305 case BCM_COSQ_STRICT: 2306 mbits = 0; 2307 break; 2308 case BCM_COSQ_ROUND_ROBIN: 2309 mbits = 1; 2310 break; 2311 case BCM_COSQ_WEIGHTED_ROUND_ROBIN: 2312 case BCM_COSQ_DEFICIT_ROUND_ROBIN: 2313 if (BCM_PBMP_NEQ(pbm, PBMP_CMIC(unit))) { 2314 continue; 2315 } 2316 return BCM_E_PARAM; 2317 default: 2318 return BCM_E_PARAM; 2319 } 2320 2321 if (SOC_IS_TR_VL(unit)) { 2322 SOC_IF_ERROR_RETURN(READ_ES_CPU_SCHEDULERr(unit, &rval)); 2323 soc_reg_field_set(unit, ES_CPU_SCHEDULERr, &rval, MODEf, 2324 mbits); 2325 SOC_IF_ERROR_RETURN(WRITE_ES_CPU_SCHEDULERr(unit, rval)); 2326 continue; 2327 } /* Scorpion uses the call below for allowed modes on CPU */ 2328 } 2329 2330 BCM_IF_ERROR_RETURN 2331 (_bcm_tr_cosq_port_sched_set(unit, 2332 ESCONFIGr, COSWEIGHTSr, 2333 MINSPCONFIGr, 2334 port, 0, 8, weights, mode)); 2335 } 2336 return BCM_E_NONE; 2337 } 2338 2339 /* 2340 * Function: 2341 * bcm_cosq_port_sched_get 2342 * Purpose: 2343 * Retrieve class-of-service policy and corresponding weights and delay 2344 * Parameters: 2345 * unit - StrataSwitch unit number. 2346 * pbm - port bitmap 2347 * mode - (output) Scheduling mode, one of BCM_COSQ_xxx 2348 * weights - (output) Weights for each COS queue 2349 * Only for BCM_COSQ_WEIGHTED_ROUND_ROBIN and 2350 * BCM_COSQ_DEFICIT_ROUND_ROBIN mode. 2351 * For DRR Weight is specified in Kbytes 2352 * delay - This parameter is not used 2353 * Returns: 2354 * BCM_E_XXX 2355 * Notes: 2356 * Actually just returns data for the first port in the bitmap 2357 */ 2358 2359 int 2360 bcm_tr_cosq_port_sched_get(int unit, bcm_pbmp_t pbm, 2361 int *mode, int weights[], int *delay) 2362 { 2363 bcm_port_t port; 2364 uint32 rval; 2365 2366 PBMP_ITER(pbm, port) { 2367 /* coverity[overrun-local : FALSE] */ 2368 if (IS_CPU_PORT(unit, port)) { 2369 if (BCM_PBMP_NEQ(pbm, PBMP_CMIC(unit))) { 2370 continue; 2371 } 2372 if (SOC_IS_TR_VL(unit) && !SOC_IS_ENDURO(unit)) { 2373 SOC_IF_ERROR_RETURN(READ_ES_CPU_SCHEDULERr(unit, &rval)); 2374 if (soc_reg_field_get(unit, ES_CPU_SCHEDULERr, 2375 rval, MODEf)) { 2376 *mode = BCM_COSQ_ROUND_ROBIN; 2377 } else { 2378 *mode = BCM_COSQ_STRICT; 2379 } 2380 return BCM_E_NONE; 2381 } /* Scorpion uses the call below for CPU */ 2382 } 2383 BCM_IF_ERROR_RETURN 2384 (_bcm_tr_cosq_port_sched_get(unit, ESCONFIGr, COSWEIGHTSr, 2385 port, 0, 8, weights, mode)); 2386 break; 2387 } 2388 return BCM_E_NONE; 2389 } 2390 2391 /* 2392 * Function: 2393 * bcm_tr_cosq_sched_weight_max_get 2394 * Purpose: 2395 * Retrieve maximum weights for given COS policy. 2396 * Parameters: 2397 * unit - StrataSwitch unit number. 2398 * mode - Scheduling mode, one of BCM_COSQ_xxx 2399 * weight_max - (output) Maximum weight for COS queue. 2400 * For DRR mode Weight is specified in Kbytes 2401 * 0 if mode is BCM_COSQ_STRICT. 2402 * 1 if mode is BCM_COSQ_ROUND_ROBIN. 2403 * -1 if not applicable to mode. 2404 * Returns: 2405 * BCM_E_XXX 2406 */ 2407 2408 int 2409 bcm_tr_cosq_sched_weight_max_get(int unit, int mode, int *weight_max) 2410 { 2411 switch (mode) { 2412 case BCM_COSQ_STRICT: 2413 *weight_max = BCM_COSQ_WEIGHT_STRICT; 2414 break; 2415 case BCM_COSQ_ROUND_ROBIN: 2416 *weight_max = BCM_COSQ_WEIGHT_MIN; 2417 break; 2418 case BCM_COSQ_WEIGHTED_ROUND_ROBIN: 2419 *weight_max = TR_WRR_WEIGHT_MAX; 2420 break; 2421 case BCM_COSQ_DEFICIT_ROUND_ROBIN: 2422 *weight_max = TR_DRR_WEIGHT_MAX * 16; /* Maximum MTU quanta */ 2423 break; 2424 default: 2425 *weight_max = BCM_COSQ_WEIGHT_UNLIMITED; 2426 return BCM_E_PARAM; 2427 } 2428 2429 return BCM_E_NONE; 2430 } 2431 2432 /* 2433 * Function: 2434 * bcm_cosq_gport_add 2435 * Purpose: 2436 * 2437 * Parameters: 2438 * unit - (IN) Unit number. 2439 * port - (IN) Physical port. 2440 * numq - (IN) Number of COS queues. 2441 * flags - (IN) Flags. 2442 * gport - (IN/OUT) GPORT ID. 2443 * Returns: 2444 * BCM_E_XXX 2445 */ 2446 int 2447 bcm_tr_cosq_gport_add(int unit, bcm_gport_t port, int numq, 2448 uint32 flags, bcm_gport_t *gport) 2449 { 2450 bcm_module_t modid, mod_out; 2451 bcm_port_t local_port, port_out; 2452 bcm_trunk_t trunk_id; 2453 int gport_id; 2454 2455 if ((numq <= 0) || (numq > 16) || 2456 (!BCM_GPORT_IS_LOCAL(port) && !BCM_GPORT_IS_MODPORT(port))) { 2457 return BCM_E_PARAM; 2458 } 2459 if (flags & (BCM_COSQ_GPORT_WITH_ID | BCM_COSQ_GPORT_OVERLAY | 2460 BCM_COSQ_GPORT_UCAST_QUEUE_GROUP | BCM_COSQ_GPORT_MCAST_QUEUE | 2461 BCM_COSQ_GPORT_MCAST_QUEUE_GROUP | BCM_COSQ_GPORT_SUBSCRIBER | 2462 BCM_COSQ_GPORT_EGRESS_GROUP | BCM_COSQ_GPORT_DISABLE | 2463 BCM_COSQ_GPORT_CALENDAR)) { 2464 return BCM_E_UNAVAIL; 2465 } 2466 2467 BCM_IF_ERROR_RETURN 2468 (_bcm_tr_cosq_resolve_mod_port(unit, port, &modid, 2469 &local_port, &trunk_id)); 2470 2471 /* Verify that the specified port is for my modid and that 2472 * it is capable of hierarchical queueing. 2473 */ 2474 if (!_tr_num_port_cosq[unit]) { 2475 return BCM_E_INIT; 2476 } else if (!SOC_PBMP_MEMBER(_tr_cosq_24q_ports[unit], local_port)) { 2477 return BCM_E_PORT; 2478 } else if (_tr_num_port_cosq[unit][local_port]) { 2479 return BCM_E_EXISTS; 2480 } 2481 /* Call delete routine to init HW settings */ 2482 BCM_IF_ERROR_RETURN (_bcm_tr_cosq_gport_delete(unit, local_port)); 2483 2484 _tr_num_port_cosq[unit][local_port] = numq; 2485 2486 /* The GPORT ID for SCHEDULER is the modid/port from application 2487 * space. This allows the GPORT ID to be used on remote module 2488 * API calls. Convert from local space to application space. 2489 */ 2490 BCM_IF_ERROR_RETURN 2491 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET, 2492 modid, local_port, &mod_out, &port_out)); 2493 gport_id = (mod_out << 8) | port_out; 2494 BCM_GPORT_SCHEDULER_SET(*gport, gport_id); 2495 return BCM_E_NONE; 2496 } 2497 2498 STATIC int 2499 _bcm_tr_cosq_gport_delete(int unit, bcm_port_t port) 2500 { 2501 int cosq, weights[16]; 2502 uint32 val; 2503 2504 /* Detach from physical port */ 2505 BCM_IF_ERROR_RETURN 2506 (soc_reg_field32_modify(unit, COS_MODEr, port, SELECTf, 0x0)); 2507 BCM_IF_ERROR_RETURN 2508 (soc_reg_field32_modify(unit, ING_COS_MODEr, port, SELECTf, 0x0)); 2509 2510 /* Clear bandwidth of all Stage1 COSQs */ 2511 for (cosq = 8; cosq < 24; cosq++) { 2512 BCM_IF_ERROR_RETURN 2513 (bcm_tr_cosq_port_bandwidth_set(unit, port, cosq, 0, 0, 0, 0)); 2514 } 2515 2516 /* Clear bandwidth of S1 output queue */ 2517 cosq = 24; 2518 BCM_IF_ERROR_RETURN 2519 (bcm_tr_cosq_port_bandwidth_set(unit, port, cosq, 0, 0, 0, 0)); 2520 2521 /* Clear weights of all Stage1 COSQs */ 2522 for (cosq = 0; cosq < 16; cosq++) { 2523 weights[cosq] = 0; 2524 } 2525 BCM_IF_ERROR_RETURN 2526 (_bcm_tr_cosq_port_sched_set(unit, S1V_CONFIGr, S1V_COSWEIGHTSr, 2527 S1V_MINSPCONFIGr, port, 0, 16, 2528 weights, BCM_COSQ_WEIGHTED_ROUND_ROBIN)); 2529 2530 /* Clear weight for S1 output queue */ 2531 cosq = 8; 2532 BCM_IF_ERROR_RETURN(READ_COSWEIGHTSr(unit, port, cosq, &val)); 2533 soc_reg_field_set(unit, COSWEIGHTSr, &val, COSWEIGHTSf, 0); 2534 BCM_IF_ERROR_RETURN(WRITE_COSWEIGHTSr(unit, port, cosq, val)); 2535 2536 /* Clear discard settings for all Stage1 COSQs */ 2537 for (cosq = 8; cosq < 24; cosq++) { 2538 BCM_IF_ERROR_RETURN 2539 (_bcm_tr_cosq_discard_set(unit, port, 2540 BCM_COSQ_DISCARD_COLOR_ALL | 2541 BCM_COSQ_DISCARD_NONTCP, cosq, 2542 WREDCONFIG_PACKETr, 2543 WREDPARAM_PACKETr, 2544 WREDPARAM_YELLOW_PACKETr, 2545 WREDPARAM_RED_PACKETr, 2546 WREDPARAM_NONTCP_PACKETr, 2547 TR_PACKET_FIELD_MAX(unit), 2548 TR_PACKET_FIELD_MAX(unit), 100, 0)); 2549 } 2550 2551 _tr_num_port_cosq[unit][port] = 0; 2552 2553 return BCM_E_NONE; 2554 } 2555 2556 /* 2557 * Function: 2558 * bcm_cosq_gport_delete 2559 * Purpose: 2560 * 2561 * Parameters: 2562 * unit - (IN) Unit number. 2563 * gport - (IN) GPORT ID. 2564 * Returns: 2565 * BCM_E_XXX 2566 */ 2567 int 2568 bcm_tr_cosq_gport_delete(int unit, bcm_gport_t gport) 2569 { 2570 bcm_module_t modid; 2571 bcm_port_t local_port; 2572 bcm_trunk_t trunk_id; 2573 2574 BCM_IF_ERROR_RETURN 2575 (_bcm_tr_cosq_resolve_mod_port(unit, gport, &modid, 2576 &local_port, &trunk_id)); 2577 if (BCM_GPORT_IS_SCHEDULER(gport)) { 2578 if (!_tr_num_port_cosq[unit]) { 2579 return BCM_E_INIT; 2580 } else if (_tr_num_port_cosq[unit][local_port] == 0) { 2581 return BCM_E_NOT_FOUND; 2582 } 2583 } else if(BCM_GPORT_IS_LOCAL(gport) || 2584 BCM_GPORT_IS_MODPORT(gport)) { 2585 if (!_tr_num_port_cosq[unit]) { 2586 return BCM_E_INIT; 2587 } 2588 } else { 2589 return BCM_E_PARAM; 2590 } 2591 BCM_IF_ERROR_RETURN (_bcm_tr_cosq_gport_delete(unit, local_port)); 2592 return BCM_E_NONE; 2593 } 2594 2595 /* 2596 * Function: 2597 * bcm_cosq_gport_traverse 2598 * Purpose: 2599 * Walks through the valid COSQ GPORTs and calls 2600 * the user supplied callback function for each entry. 2601 * Parameters: 2602 * unit - (IN) bcm device. 2603 * trav_fn - (IN) Callback function. 2604 * user_data - (IN) User data to be passed to callback function. 2605 * Returns: 2606 * BCM_E_NONE - Success. 2607 * BCM_E_XXX 2608 */ 2609 int 2610 bcm_tr_cosq_gport_traverse(int unit, bcm_cosq_gport_traverse_cb cb, 2611 void *user_data) 2612 { 2613 bcm_module_t my_modid, mod_out; 2614 bcm_port_t port, port_out; 2615 bcm_gport_t gport, sched_gport; 2616 int gport_id; 2617 uint32 flags = BCM_COSQ_GPORT_SCHEDULER; 2618 int rv = SOC_E_NONE; 2619 2620 if (_tr_num_port_cosq[unit]) { 2621 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &my_modid)); 2622 BCM_PBMP_ITER(_tr_cosq_24q_ports[unit], port) { 2623 if (_tr_num_port_cosq[unit][port]) { 2624 2625 /* Construct physical port GPORT ID */ 2626 BCM_IF_ERROR_RETURN 2627 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET, 2628 my_modid, port, &mod_out, &port_out)); 2629 BCM_GPORT_MODPORT_SET(gport, mod_out, port_out); 2630 2631 /* Construct scheduler GPORT ID */ 2632 gport_id = (mod_out << 8) | port_out; 2633 BCM_GPORT_SCHEDULER_SET(sched_gport, gport_id); 2634 2635 /* Call application call-back */ 2636 rv = cb(unit, gport, _tr_num_port_cosq[unit][port], 2637 flags, sched_gport, user_data); 2638 if (BCM_FAILURE(rv)) { 2639 #ifdef BCM_CB_ABORT_ON_ERR 2640 if (SOC_CB_ABORT_ON_ERR(unit)) { 2641 return rv; 2642 } 2643 #endif 2644 } 2645 } 2646 } 2647 } else { 2648 return BCM_E_INIT; 2649 } 2650 return BCM_E_NONE; 2651 } 2652 2653 STATIC int 2654 _bcm_tr_cosq_gport_bandwidth_port_resolve(int unit, bcm_gport_t gport, 2655 bcm_cos_queue_t cosq, 2656 bcm_port_t *local_port, 2657 bcm_cos_queue_t *cosq_start, 2658 bcm_cos_queue_t *cosq_end) 2659 { 2660 bcm_module_t modid; 2661 bcm_trunk_t trunk_id; 2662 2663 if (BCM_GPORT_IS_SET(gport)) { 2664 BCM_IF_ERROR_RETURN 2665 (_bcm_tr_cosq_resolve_mod_port(unit, gport, &modid, 2666 local_port, &trunk_id)); 2667 } else { 2668 *local_port = gport; 2669 if (!SOC_PORT_VALID(unit, gport)) { 2670 return BCM_E_PORT; 2671 } 2672 } 2673 2674 if (!_tr_num_port_cosq[unit]) { 2675 return BCM_E_INIT; 2676 } 2677 2678 if (cosq < -1) { 2679 return BCM_E_PARAM; 2680 } 2681 2682 if (BCM_GPORT_IS_SCHEDULER(gport)) { 2683 if (_tr_num_port_cosq[unit][*local_port] == 0) { 2684 return BCM_E_NOT_FOUND; 2685 } else if (cosq < 0) { 2686 *cosq_start = 8; 2687 *cosq_end = 23; 2688 } else if (cosq >= _tr_num_port_cosq[unit][*local_port]) { 2689 return BCM_E_PARAM; 2690 } else { 2691 *cosq_start = *cosq_end = (cosq + 8); 2692 } 2693 } else if (cosq == TR_SCHEDULER_COSQ) { 2694 if (!SOC_PBMP_MEMBER(_tr_cosq_24q_ports[unit], *local_port)) { 2695 return BCM_E_PORT; 2696 } 2697 /* Output of S1 scheduler is configured using register offset 24 */ 2698 *cosq_start = *cosq_end = 24; 2699 } else { 2700 if (IS_CPU_PORT(unit, *local_port)) { 2701 if (cosq >= NUM_CPU_COSQ(unit)) { 2702 return BCM_E_PARAM; 2703 } else if (cosq < 0) { 2704 *cosq_start = 0; 2705 *cosq_end = NUM_CPU_COSQ(unit) - 1 ; 2706 } else { 2707 *cosq_start = *cosq_end = cosq; 2708 } 2709 } else { 2710 if (cosq >= _tr_num_cosq[unit]) { 2711 return BCM_E_PARAM; 2712 } else if (cosq < 0) { 2713 *cosq_start = 0; 2714 *cosq_end = 7; 2715 } else { 2716 *cosq_start = *cosq_end = cosq; 2717 } 2718 } 2719 } 2720 2721 return BCM_E_NONE; 2722 } 2723 2724 /* 2725 * Function: 2726 * bcm_cosq_gport_bandwidth_set 2727 * Purpose: 2728 * 2729 * Parameters: 2730 * unit - (IN) Unit number. 2731 * gport - (IN) GPORT ID. 2732 * cosq - (IN) COS queue to configure, -1 for all COS queues. 2733 * kbits_sec_min - (IN) minimum bandwidth, kbits/sec. 2734 * kbits_sec_max - (IN) maximum bandwidth, kbits/sec. 2735 * flags - (IN) BCM_COSQ_BW_* 2736 * Returns: 2737 * BCM_E_XXX 2738 */ 2739 int 2740 bcm_tr_cosq_gport_bandwidth_set(int unit, bcm_gport_t gport, 2741 bcm_cos_queue_t cosq, uint32 kbits_sec_min, 2742 uint32 kbits_sec_max, uint32 flags) 2743 { 2744 bcm_port_t local_port; 2745 int i; 2746 bcm_cos_queue_t cosq_start = 0, cosq_end = 0; 2747 2748 BCM_IF_ERROR_RETURN 2749 (_bcm_tr_cosq_gport_bandwidth_port_resolve(unit, gport, cosq, 2750 &local_port, 2751 &cosq_start, &cosq_end)); 2752 2753 for (i = cosq_start; i <= cosq_end; i++) { 2754 BCM_IF_ERROR_RETURN 2755 (bcm_tr_cosq_port_bandwidth_set(unit, local_port, i, 2756 kbits_sec_min, 2757 kbits_sec_max, 2758 kbits_sec_max, 2759 flags)); 2760 } 2761 return BCM_E_NONE; 2762 } 2763 2764 /* 2765 * Function: 2766 * bcm_cosq_gport_bandwidth_get 2767 * Purpose: 2768 * 2769 * Parameters: 2770 * unit - (IN) Unit number. 2771 * gport - (IN) GPORT ID. 2772 * cosq - (IN) COS queue to configure, -1 for all COS queues. 2773 * kbits_sec_min - (OUT) minimum bandwidth, kbits/sec. 2774 * kbits_sec_max - (OUT) maximum bandwidth, kbits/sec. 2775 * flags - (OUT) BCM_COSQ_BW_* 2776 * Returns: 2777 * BCM_E_XXX 2778 */ 2779 int 2780 bcm_tr_cosq_gport_bandwidth_get(int unit, bcm_gport_t gport, 2781 bcm_cos_queue_t cosq, uint32 *kbits_sec_min, 2782 uint32 *kbits_sec_max, uint32 *flags) 2783 { 2784 bcm_port_t local_port; 2785 bcm_cos_queue_t cosq_start = 0, cosq_end = 0; 2786 uint32 kbits_sec_burst; /* Dummy variable */ 2787 2788 *kbits_sec_min = *kbits_sec_max = *flags = 0; 2789 2790 BCM_IF_ERROR_RETURN 2791 (_bcm_tr_cosq_gport_bandwidth_port_resolve(unit, gport, cosq, 2792 &local_port, 2793 &cosq_start, &cosq_end)); 2794 2795 BCM_IF_ERROR_RETURN 2796 (bcm_tr_cosq_port_bandwidth_get(unit, local_port, cosq_start, 2797 kbits_sec_min, kbits_sec_max, 2798 &kbits_sec_burst, flags)); 2799 return BCM_E_NONE; 2800 } 2801 2802 /* 2803 * Function: 2804 * bcm_tr_cosq_gport_bandwidth_burst_set 2805 * Purpose: 2806 * 2807 * Parameters: 2808 * unit - (IN) Unit number. 2809 * gport - (IN) GPORT ID. 2810 * cosq - (IN) COS queue to configure, -1 for all COS queues. 2811 * kbits_burst - (IN) maximum burst, kbits. 2812 * Returns: 2813 * BCM_E_XXX 2814 */ 2815 int 2816 bcm_tr_cosq_gport_bandwidth_burst_set(int unit, bcm_gport_t gport, 2817 bcm_cos_queue_t cosq, 2818 uint32 kbits_burst_min, 2819 uint32 kbits_burst_max) 2820 { 2821 bcm_port_t local_port, port; 2822 int i; 2823 bcm_cos_queue_t cosq_start = 0, cosq_end = 0; 2824 uint32 kbits_sec_min, kbits_sec_max, flags; 2825 uint32 kbits_sec_burst; /* Dummy variable */ 2826 2827 if (gport < 0) { 2828 PBMP_ALL_ITER(unit, port) { 2829 BCM_IF_ERROR_RETURN 2830 (_bcm_tr_cosq_gport_bandwidth_port_resolve(unit, port, cosq, 2831 &local_port, 2832 &cosq_start, &cosq_end)); 2833 for (i = cosq_start; i <= cosq_end; i++) { 2834 BCM_IF_ERROR_RETURN 2835 (_bcm_tr_cosq_bucket_get(unit, local_port, i, 2836 &kbits_sec_min, &kbits_sec_max, 2837 &kbits_sec_burst,&kbits_sec_burst,&flags)); 2838 BCM_IF_ERROR_RETURN 2839 (_bcm_tr_cosq_bucket_set(unit, local_port, i, 2840 kbits_sec_min, 2841 kbits_sec_max, 2842 kbits_burst_min, 2843 kbits_burst_max, 2844 flags)); 2845 } 2846 } 2847 return BCM_E_NONE; 2848 } 2849 2850 BCM_IF_ERROR_RETURN 2851 (_bcm_tr_cosq_gport_bandwidth_port_resolve(unit, gport, cosq, 2852 &local_port, 2853 &cosq_start, &cosq_end)); 2854 2855 for (i = cosq_start; i <= cosq_end; i++) { 2856 BCM_IF_ERROR_RETURN 2857 (_bcm_tr_cosq_bucket_get(unit, local_port, cosq_start, 2858 &kbits_sec_min, &kbits_sec_max, 2859 &kbits_sec_burst, &kbits_sec_burst,&flags)); 2860 BCM_IF_ERROR_RETURN 2861 (_bcm_tr_cosq_bucket_set(unit, local_port, i, 2862 kbits_sec_min, 2863 kbits_sec_max, 2864 kbits_burst_min, 2865 kbits_burst_max, 2866 flags)); 2867 } 2868 return BCM_E_NONE; 2869 } 2870 2871 /* 2872 * Function: 2873 * bcm_tr_cosq_gport_bandwidth_burst_get 2874 * Purpose: 2875 * 2876 * Parameters: 2877 * unit - (IN) Unit number. 2878 * gport - (IN) GPORT ID. 2879 * cosq - (IN) COS queue to configure, -1 for all COS queues. 2880 * kbits_burst - (OUT) maximum burst, kbits. 2881 * Returns: 2882 * BCM_E_XXX 2883 */ 2884 int 2885 bcm_tr_cosq_gport_bandwidth_burst_get(int unit, bcm_gport_t gport, 2886 bcm_cos_queue_t cosq, 2887 uint32 *kbits_burst_min, 2888 uint32 *kbits_burst_max) 2889 { 2890 bcm_port_t local_port, port; 2891 bcm_cos_queue_t cosq_start = 0, cosq_end = 0; 2892 uint32 kbits_sec_min, kbits_sec_max, flags; /* Dummy variables */ 2893 2894 if (gport < 0) { 2895 port = SOC_PORT_MIN(unit,all); 2896 2897 BCM_IF_ERROR_RETURN 2898 (_bcm_tr_cosq_gport_bandwidth_port_resolve(unit, port, cosq, 2899 &local_port, 2900 &cosq_start, &cosq_end)); 2901 } else { 2902 BCM_IF_ERROR_RETURN 2903 (_bcm_tr_cosq_gport_bandwidth_port_resolve(unit, gport, cosq, 2904 &local_port, 2905 &cosq_start, &cosq_end)); 2906 } 2907 2908 kbits_sec_min = kbits_sec_max = flags = 0; 2909 2910 BCM_IF_ERROR_RETURN 2911 (_bcm_tr_cosq_bucket_get(unit, local_port, cosq_start, 2912 &kbits_sec_min, &kbits_sec_max, 2913 kbits_burst_min,kbits_burst_max, &flags)); 2914 return BCM_E_NONE; 2915 } 2916 2917 /* 2918 * Function: 2919 * bcm_cosq_gport_sched_set 2920 * Purpose: 2921 * 2922 * Parameters: 2923 * unit - (IN) Unit number. 2924 * gport - (IN) GPORT ID. 2925 * cosq - (IN) COS queue to configure, -1 for all COS queues. 2926 * mode - (IN) Scheduling mode, one of BCM_COSQ_xxx 2927 * weight - (IN) Weight for the specified COS queue(s) 2928 * Unused if mode is BCM_COSQ_STRICT. 2929 * Returns: 2930 * BCM_E_XXX 2931 */ 2932 int 2933 bcm_tr_cosq_gport_sched_set(int unit, bcm_gport_t gport, 2934 bcm_cos_queue_t cosq, int mode, int weight) 2935 { 2936 bcm_module_t modid; 2937 bcm_port_t local_port; 2938 bcm_trunk_t trunk_id; 2939 int i; 2940 int numq; 2941 bcm_cos_queue_t cosq_start = 0; 2942 int num_weights = 1, weights[64]; 2943 soc_reg_t config_reg = ESCONFIGr; 2944 soc_reg_t weight_reg = COSWEIGHTSr; 2945 soc_reg_t minsp_reg = MINSPCONFIGr; 2946 2947 BCM_IF_ERROR_RETURN 2948 (_bcm_tr_cosq_resolve_mod_port(unit, gport, &modid, 2949 &local_port, &trunk_id)); 2950 2951 if (!_tr_num_port_cosq[unit]) { 2952 return BCM_E_INIT; 2953 } 2954 if (BCM_GPORT_IS_SCHEDULER(gport)) { 2955 if (_tr_num_port_cosq[unit][local_port] == 0) { 2956 return BCM_E_NOT_FOUND; 2957 } else if (cosq >= _tr_num_port_cosq[unit][local_port]) { 2958 return BCM_E_PARAM; 2959 } else if (cosq < 0) { 2960 cosq_start = 0; 2961 num_weights = 16; 2962 for (i = 0; i < num_weights; i++) { 2963 if (i < _tr_num_port_cosq[unit][local_port]) { 2964 weights[i] = weight; 2965 } else { 2966 weights[i] = 0; 2967 } 2968 } 2969 } else { 2970 cosq_start = cosq; 2971 num_weights = 1; 2972 weights[0] = weight; 2973 } 2974 config_reg = S1V_CONFIGr; 2975 weight_reg = S1V_COSWEIGHTSr; 2976 minsp_reg = S1V_MINSPCONFIGr; 2977 } else if (IS_CPU_PORT(unit, local_port)) { 2978 numq = SOC_INFO(unit).num_cpu_cosq; 2979 if (cosq >= numq) { 2980 return BCM_E_PARAM; 2981 } else if (cosq < 0) { 2982 cosq_start = 0; 2983 num_weights = NUM_CPU_COSQ(unit); 2984 for (i = 0; i < num_weights; i++) { 2985 weights[i] = weight; 2986 } 2987 } else { 2988 cosq_start = cosq; 2989 num_weights = 1; 2990 weights[0] = weight; 2991 } 2992 } else if (cosq == TR_SCHEDULER_COSQ) { 2993 if (!SOC_PBMP_MEMBER(_tr_cosq_24q_ports[unit], local_port)) { 2994 return BCM_E_PORT; 2995 } 2996 /* Weight for output of S1 scheduler is configured using offset 8 2997 * of COSWEIGHTS register. 2998 */ 2999 cosq_start = 8; 3000 num_weights = 1; 3001 weights[0] = weight; 3002 } else { 3003 if (cosq >= _tr_num_cosq[unit]) { 3004 return BCM_E_PARAM; 3005 } else if (cosq < 0) { 3006 cosq_start = 0; 3007 num_weights = 8; 3008 for (i = 0; i < num_weights; i++) { 3009 if (i < _tr_num_cosq[unit]) { 3010 weights[i] = weight; 3011 } else { 3012 weights[i] = 0; 3013 } 3014 } 3015 } else { 3016 cosq_start = cosq; 3017 num_weights = 1; 3018 weights[0] = weight; 3019 } 3020 } 3021 3022 /* coverity[uninit_use_in_call : FALSE] */ 3023 BCM_IF_ERROR_RETURN 3024 (_bcm_tr_cosq_port_sched_set(unit, config_reg, weight_reg, minsp_reg, 3025 local_port, cosq_start, num_weights, 3026 weights, mode)); 3027 return BCM_E_NONE; 3028 } 3029 3030 /* 3031 * Function: 3032 * bcm_cosq_gport_sched_get 3033 * Purpose: 3034 * 3035 * Parameters: 3036 * unit - (IN) Unit number. 3037 * gport - (IN) GPORT ID. 3038 * cosq - (IN) COS queue 3039 * mode - (OUT) Scheduling mode, one of BCM_COSQ_xxx 3040 * weight - (OUT) Weight for the specified COS queue(s) 3041 * Unused if mode is BCM_COSQ_STRICT. 3042 * Returns: 3043 * BCM_E_XXX 3044 */ 3045 int 3046 bcm_tr_cosq_gport_sched_get(int unit, bcm_gport_t gport, 3047 bcm_cos_queue_t cosq, int *mode, int *weight) 3048 { 3049 bcm_module_t modid; 3050 bcm_port_t local_port; 3051 bcm_trunk_t trunk_id; 3052 soc_reg_t config_reg = ESCONFIGr; 3053 soc_reg_t weight_reg = COSWEIGHTSr; 3054 3055 *mode = *weight = 0; 3056 3057 BCM_IF_ERROR_RETURN 3058 (_bcm_tr_cosq_resolve_mod_port(unit, gport, &modid, 3059 &local_port, &trunk_id)); 3060 if (!_tr_num_port_cosq[unit]) { 3061 return BCM_E_INIT; 3062 } 3063 if (BCM_GPORT_IS_SCHEDULER(gport)) { 3064 if (_tr_num_port_cosq[unit][local_port] == 0) { 3065 return BCM_E_NOT_FOUND; 3066 } else if (cosq >= _tr_num_port_cosq[unit][local_port]) { 3067 return BCM_E_PARAM; 3068 } else if (cosq < 0) { 3069 cosq = 0; 3070 } 3071 config_reg = S1V_CONFIGr; 3072 weight_reg = S1V_COSWEIGHTSr; 3073 } else if (cosq == TR_SCHEDULER_COSQ) { 3074 if (!SOC_PBMP_MEMBER(_tr_cosq_24q_ports[unit], local_port)) { 3075 return BCM_E_PORT; 3076 } 3077 /* Weight for output of S1 scheduler is configured using offset 8 3078 * of COSWEIGHTS register. 3079 */ 3080 cosq = 8; 3081 } else { 3082 if (cosq >= _tr_num_cosq[unit]) { 3083 return BCM_E_PARAM; 3084 } else if (cosq < 0) { 3085 cosq = 0; 3086 } 3087 } 3088 BCM_IF_ERROR_RETURN 3089 (_bcm_tr_cosq_port_sched_get(unit, config_reg, weight_reg, 3090 local_port, cosq, 1, 3091 weight, mode)); 3092 return BCM_E_NONE; 3093 } 3094 3095 /* 3096 * Function: 3097 * bcm_cosq_gport_discard_set 3098 * Purpose: 3099 * 3100 * Parameters: 3101 * unit - (IN) Unit number. 3102 * port - (IN) GPORT ID. 3103 * cosq - (IN) COS queue to configure 3104 * discard - (IN) Discard settings 3105 * Returns: 3106 * BCM_E_XXX 3107 */ 3108 int 3109 bcm_tr_cosq_gport_discard_set(int unit, bcm_gport_t port, bcm_cos_queue_t cosq, 3110 bcm_cosq_gport_discard_t *discard) 3111 { 3112 bcm_module_t modid; 3113 bcm_port_t local_port; 3114 bcm_trunk_t trunk_id; 3115 uint32 min_thresh, max_thresh; 3116 int cell_size, cell_field_max; 3117 3118 if ((discard == NULL) || 3119 (discard->gain < 0) || (discard->gain > 15) || 3120 (discard->drop_probability < 0) || (discard->drop_probability > 100)) { 3121 return BCM_E_PARAM; 3122 } 3123 3124 #ifdef BCM_SCORPION_SUPPORT 3125 if (SOC_IS_SC_CQ(unit)) { 3126 if (!(discard->flags & BCM_COSQ_DISCARD_BYTES)) { 3127 /* Scorpion only supports byte accounting for WRED */ 3128 return BCM_E_UNAVAIL; 3129 } 3130 cell_size = _BCM_SC_COSQ_CELLSIZE; 3131 cell_field_max = SC_CELL_FIELD_MAX; 3132 } else 3133 #endif /* BCM_SCORPION_SUPPORT */ 3134 { 3135 cell_size = _BCM_TR_COSQ_CELLSIZE; 3136 cell_field_max = TR_CELL_FIELD_MAX(unit); 3137 } 3138 3139 min_thresh = discard->min_thresh; 3140 max_thresh = discard->max_thresh; 3141 if (discard->flags & BCM_COSQ_DISCARD_BYTES) { 3142 /* Convert bytes to cells */ 3143 min_thresh += (cell_size - 1); 3144 min_thresh /= cell_size; 3145 3146 max_thresh += (cell_size - 1); 3147 max_thresh /= cell_size; 3148 3149 if ((min_thresh > cell_field_max) || 3150 (max_thresh > cell_field_max)) { 3151 return BCM_E_PARAM; 3152 } 3153 } else { /* BCM_COSQ_DISCARD_PACKETS */ 3154 if ((min_thresh > TR_PACKET_FIELD_MAX(unit)) || 3155 (max_thresh > TR_PACKET_FIELD_MAX(unit))) { 3156 return BCM_E_PARAM; 3157 } 3158 } 3159 3160 if (port != BCM_GPORT_INVALID) { 3161 BCM_IF_ERROR_RETURN 3162 (_bcm_tr_cosq_resolve_mod_port(unit, port, &modid, 3163 &local_port, &trunk_id)); 3164 if (cosq < 0) { 3165 /* per-port discard settings */ 3166 if (discard->flags & BCM_COSQ_DISCARD_BYTES) { 3167 BCM_IF_ERROR_RETURN 3168 (_bcm_tr_cosq_discard_set(unit, local_port, 3169 discard->flags, 0, 3170 PORT_WREDCONFIG_CELLr, 3171 PORT_WREDPARAM_CELLr, 3172 PORT_WREDPARAM_YELLOW_CELLr, 3173 PORT_WREDPARAM_RED_CELLr, 3174 PORT_WREDPARAM_NONTCP_CELLr, 3175 min_thresh, max_thresh, 3176 discard->drop_probability, 3177 discard->gain)); 3178 BCM_IF_ERROR_RETURN 3179 (_bcm_tr_cosq_discard_cap_enable_set(unit, local_port, 0, 3180 PORT_WREDCONFIG_CELLr, 3181 discard->flags)); 3182 3183 } else { /* BCM_COSQ_DISCARD_PACKETS */ 3184 BCM_IF_ERROR_RETURN 3185 (_bcm_tr_cosq_discard_set(unit, local_port, 3186 discard->flags, 0, 3187 PORT_WREDCONFIG_PACKETr, 3188 PORT_WREDPARAM_PACKETr, 3189 PORT_WREDPARAM_YELLOW_PACKETr, 3190 PORT_WREDPARAM_RED_PACKETr, 3191 PORT_WREDPARAM_NONTCP_PACKETr, 3192 min_thresh, max_thresh, 3193 discard->drop_probability, 3194 discard->gain)); 3195 BCM_IF_ERROR_RETURN 3196 (_bcm_tr_cosq_discard_cap_enable_set(unit, local_port, 0, 3197 PORT_WREDCONFIG_PACKETr, 3198 discard->flags)); 3199 } 3200 } else { 3201 /* per-port/per-cos discard settings */ 3202 if (BCM_GPORT_IS_SCHEDULER(port)) { 3203 if (_tr_num_port_cosq[unit][local_port] == 0) { 3204 return BCM_E_NOT_FOUND; 3205 } else if (cosq >= _tr_num_port_cosq[unit][local_port]) { 3206 return BCM_E_PARAM; 3207 } else { 3208 cosq = cosq + 8; 3209 } 3210 } else if (cosq >= _tr_num_cosq[unit]) { 3211 return BCM_E_PARAM; 3212 } 3213 3214 if (discard->flags & BCM_COSQ_DISCARD_BYTES) { 3215 BCM_IF_ERROR_RETURN 3216 (_bcm_tr_cosq_discard_set(unit, local_port, 3217 discard->flags, cosq, 3218 WREDCONFIG_CELLr, 3219 WREDPARAM_CELLr, 3220 WREDPARAM_YELLOW_CELLr, 3221 WREDPARAM_RED_CELLr, 3222 WREDPARAM_NONTCP_CELLr, 3223 min_thresh, max_thresh, 3224 discard->drop_probability, 3225 discard->gain)); 3226 BCM_IF_ERROR_RETURN 3227 (_bcm_tr_cosq_discard_cap_enable_set(unit, local_port, cosq, 3228 WREDCONFIG_CELLr, 3229 discard->flags)); 3230 } else { /* BCM_COSQ_DISCARD_PACKETS */ 3231 BCM_IF_ERROR_RETURN 3232 (_bcm_tr_cosq_discard_set(unit, local_port, 3233 discard->flags, cosq, 3234 WREDCONFIG_PACKETr, 3235 WREDPARAM_PACKETr, 3236 WREDPARAM_YELLOW_PACKETr, 3237 WREDPARAM_RED_PACKETr, 3238 WREDPARAM_NONTCP_PACKETr, 3239 min_thresh, max_thresh, 3240 discard->drop_probability, 3241 discard->gain)); 3242 BCM_IF_ERROR_RETURN 3243 (_bcm_tr_cosq_discard_cap_enable_set(unit, local_port, cosq, 3244 WREDCONFIG_PACKETr, 3245 discard->flags)); 3246 } 3247 } 3248 } else { 3249 /* chip-wide discard settings */ 3250 if (discard->flags & BCM_COSQ_DISCARD_BYTES) { 3251 BCM_IF_ERROR_RETURN 3252 (_bcm_tr_cosq_discard_set(unit, REG_PORT_ANY, discard->flags, 3253 0, GLOBAL_WREDCONFIG_CELLr, 3254 GLOBAL_WREDPARAM_CELLr, 3255 GLOBAL_WREDPARAM_YELLOW_CELLr, 3256 GLOBAL_WREDPARAM_RED_CELLr, 3257 GLOBAL_WREDPARAM_NONTCP_CELLr, 3258 min_thresh, max_thresh, 3259 discard->drop_probability, 3260 discard->gain)); 3261 BCM_IF_ERROR_RETURN 3262 (_bcm_tr_cosq_discard_cap_enable_set(unit, REG_PORT_ANY, 0, 3263 GLOBAL_WREDCONFIG_CELLr, 3264 discard->flags)); 3265 } else { /* BCM_COSQ_DISCARD_PACKETS */ 3266 BCM_IF_ERROR_RETURN 3267 (_bcm_tr_cosq_discard_set(unit, REG_PORT_ANY, discard->flags, 3268 0, GLOBAL_WREDCONFIG_PACKETr, 3269 GLOBAL_WREDPARAM_PACKETr, 3270 GLOBAL_WREDPARAM_YELLOW_PACKETr, 3271 GLOBAL_WREDPARAM_RED_PACKETr, 3272 GLOBAL_WREDPARAM_NONTCP_PACKETr, 3273 min_thresh, max_thresh, 3274 discard->drop_probability, 3275 discard->gain)); 3276 BCM_IF_ERROR_RETURN 3277 (_bcm_tr_cosq_discard_cap_enable_set(unit, REG_PORT_ANY, 0, 3278 GLOBAL_WREDCONFIG_PACKETr, 3279 discard->flags)); 3280 } 3281 } 3282 return BCM_E_NONE; 3283 } 3284 3285 /* 3286 * Function: 3287 * bcm_cosq_gport_discard_get 3288 * Purpose: 3289 * 3290 * Parameters: 3291 * unit - (IN) Unit number. 3292 * port - (IN) GPORT ID. 3293 * cosq - (IN) COS queue to get 3294 * discard - (IN/OUT) Discard settings 3295 * Returns: 3296 * BCM_E_XXX 3297 */ 3298 int 3299 bcm_tr_cosq_gport_discard_get(int unit, bcm_gport_t port, bcm_cos_queue_t cosq, 3300 bcm_cosq_gport_discard_t *discard) 3301 { 3302 bcm_module_t modid; 3303 bcm_port_t local_port; 3304 bcm_trunk_t trunk_id; 3305 uint32 min_thresh, max_thresh; 3306 3307 if (discard == NULL) { 3308 return BCM_E_PARAM; 3309 } 3310 #ifdef BCM_SCORPION_SUPPORT 3311 if (SOC_IS_SC_CQ(unit)) { 3312 if (!(discard->flags & BCM_COSQ_DISCARD_BYTES)) { 3313 return BCM_E_UNAVAIL; 3314 } 3315 } 3316 #endif 3317 3318 if (port != BCM_GPORT_INVALID) { 3319 BCM_IF_ERROR_RETURN 3320 (_bcm_tr_cosq_resolve_mod_port(unit, port, &modid, 3321 &local_port, &trunk_id)); 3322 if (cosq < 0) { 3323 /* per-port discard settings */ 3324 if (discard->flags & BCM_COSQ_DISCARD_BYTES) { 3325 BCM_IF_ERROR_RETURN 3326 (_bcm_tr_cosq_discard_get(unit, local_port, 3327 discard->flags, 0, 3328 PORT_WREDCONFIG_CELLr, 3329 PORT_WREDPARAM_CELLr, 3330 PORT_WREDPARAM_YELLOW_CELLr, 3331 PORT_WREDPARAM_RED_CELLr, 3332 PORT_WREDPARAM_NONTCP_CELLr, 3333 &min_thresh, &max_thresh, 3334 &discard->drop_probability, 3335 &discard->gain)); 3336 BCM_IF_ERROR_RETURN 3337 (_bcm_tr_cosq_discard_cap_enable_get(unit, local_port, 0, 3338 PORT_WREDCONFIG_CELLr, 3339 &discard->flags)); 3340 } else { /* BCM_COSQ_DISCARD_PACKETS */ 3341 BCM_IF_ERROR_RETURN 3342 (_bcm_tr_cosq_discard_get(unit, local_port, 3343 discard->flags, 0, 3344 PORT_WREDCONFIG_PACKETr, 3345 PORT_WREDPARAM_PACKETr, 3346 PORT_WREDPARAM_YELLOW_PACKETr, 3347 PORT_WREDPARAM_RED_PACKETr, 3348 PORT_WREDPARAM_NONTCP_PACKETr, 3349 &min_thresh, &max_thresh, 3350 &discard->drop_probability, 3351 &discard->gain)); 3352 BCM_IF_ERROR_RETURN 3353 (_bcm_tr_cosq_discard_cap_enable_get(unit, local_port, 0, 3354 PORT_WREDCONFIG_PACKETr, 3355 &discard->flags)); 3356 } 3357 } else { 3358 /* per-port/per-cos discard settings */ 3359 if (SOC_IS_TR_VL(unit)) { 3360 if (BCM_GPORT_IS_SCHEDULER(port)) { 3361 if (_tr_num_port_cosq[unit][local_port] == 0) { 3362 return BCM_E_NOT_FOUND; 3363 } else if (cosq >= _tr_num_port_cosq[unit][local_port]) { 3364 return BCM_E_PARAM; 3365 } else { 3366 cosq = cosq + 8; 3367 } 3368 } else if (cosq >= _tr_num_cosq[unit]) { 3369 return BCM_E_PARAM; 3370 } 3371 } else { 3372 if (cosq < BCM_COS_MIN || cosq > BCM_COS_MAX) { 3373 return BCM_E_PARAM; 3374 } 3375 } 3376 3377 if (discard->flags & BCM_COSQ_DISCARD_BYTES) { 3378 BCM_IF_ERROR_RETURN 3379 (_bcm_tr_cosq_discard_get(unit, local_port, 3380 discard->flags, cosq, 3381 WREDCONFIG_CELLr, 3382 WREDPARAM_CELLr, 3383 WREDPARAM_YELLOW_CELLr, 3384 WREDPARAM_RED_CELLr, 3385 WREDPARAM_NONTCP_CELLr, 3386 &min_thresh, &max_thresh, 3387 &discard->drop_probability, 3388 &discard->gain)); 3389 BCM_IF_ERROR_RETURN 3390 (_bcm_tr_cosq_discard_cap_enable_get(unit, local_port, cosq, 3391 WREDCONFIG_CELLr, 3392 &discard->flags)); 3393 } else { /* BCM_COSQ_DISCARD_PACKETS */ 3394 BCM_IF_ERROR_RETURN 3395 (_bcm_tr_cosq_discard_get(unit, local_port, 3396 discard->flags, cosq, 3397 WREDCONFIG_PACKETr, 3398 WREDPARAM_PACKETr, 3399 WREDPARAM_YELLOW_PACKETr, 3400 WREDPARAM_RED_PACKETr, 3401 WREDPARAM_NONTCP_PACKETr, 3402 &min_thresh, &max_thresh, 3403 &discard->drop_probability, 3404 &discard->gain)); 3405 BCM_IF_ERROR_RETURN 3406 (_bcm_tr_cosq_discard_cap_enable_get(unit, local_port, cosq, 3407 WREDCONFIG_PACKETr, 3408 &discard->flags)); 3409 } 3410 } 3411 } else { 3412 /* chip-wide discard settings */ 3413 if (discard->flags & BCM_COSQ_DISCARD_BYTES) { 3414 BCM_IF_ERROR_RETURN 3415 (_bcm_tr_cosq_discard_get(unit, REG_PORT_ANY, discard->flags, 3416 0, GLOBAL_WREDCONFIG_CELLr, 3417 GLOBAL_WREDPARAM_CELLr, 3418 GLOBAL_WREDPARAM_YELLOW_CELLr, 3419 GLOBAL_WREDPARAM_RED_CELLr, 3420 GLOBAL_WREDPARAM_NONTCP_CELLr, 3421 &min_thresh, &max_thresh, 3422 &discard->drop_probability, 3423 &discard->gain)); 3424 BCM_IF_ERROR_RETURN 3425 (_bcm_tr_cosq_discard_cap_enable_get(unit, REG_PORT_ANY, 0, 3426 GLOBAL_WREDCONFIG_CELLr, 3427 &discard->flags)); 3428 } else { /* BCM_COSQ_DISCARD_PACKETS */ 3429 BCM_IF_ERROR_RETURN 3430 (_bcm_tr_cosq_discard_get(unit, REG_PORT_ANY, discard->flags, 3431 0, GLOBAL_WREDCONFIG_PACKETr, 3432 GLOBAL_WREDPARAM_PACKETr, 3433 GLOBAL_WREDPARAM_YELLOW_PACKETr, 3434 GLOBAL_WREDPARAM_RED_PACKETr, 3435 GLOBAL_WREDPARAM_NONTCP_PACKETr, 3436 &min_thresh, &max_thresh, 3437 &discard->drop_probability, 3438 &discard->gain)); 3439 BCM_IF_ERROR_RETURN 3440 (_bcm_tr_cosq_discard_cap_enable_get(unit, REG_PORT_ANY, 0, 3441 GLOBAL_WREDCONFIG_PACKETr, 3442 &discard->flags)); 3443 } 3444 } 3445 3446 if (discard->flags & BCM_COSQ_DISCARD_BYTES) { 3447 /* Convert cells to bytes */ 3448 min_thresh *= _BCM_TR_COSQ_CELLSIZE; 3449 max_thresh *= _BCM_TR_COSQ_CELLSIZE; 3450 } 3451 discard->min_thresh = min_thresh; 3452 discard->max_thresh = max_thresh; 3453 3454 return BCM_E_NONE; 3455 } 3456 3457 /* 3458 * Function: 3459 * bcm_cosq_gport_attach 3460 * Purpose: 3461 * 3462 * Parameters: 3463 * unit - (IN) Unit number. 3464 * sched_port - (IN) Scheduler GPORT ID. 3465 * input_port - (IN) GPORT to attach to. 3466 * cosq - (IN) COS queue to attach to. 3467 * Returns: 3468 * BCM_E_XXX 3469 */ 3470 int 3471 bcm_tr_cosq_gport_attach(int unit, bcm_gport_t sched_gport, 3472 bcm_gport_t input_gport, bcm_cos_queue_t cosq) 3473 { 3474 bcm_module_t sched_modid, input_modid; 3475 bcm_port_t sched_port, input_port; 3476 bcm_trunk_t trunk_id; 3477 3478 if (!BCM_GPORT_IS_SCHEDULER(sched_gport)) { 3479 return BCM_E_PARAM; 3480 } else if (!_tr_num_port_cosq[unit]) { 3481 return BCM_E_INIT; 3482 } else if (cosq < 0) { 3483 cosq = TR_SCHEDULER_COSQ; 3484 } else if (cosq != TR_SCHEDULER_COSQ) { 3485 return BCM_E_PARAM; 3486 } 3487 3488 BCM_IF_ERROR_RETURN 3489 (_bcm_tr_cosq_resolve_mod_port(unit, sched_gport, &sched_modid, 3490 &sched_port, &trunk_id)); 3491 3492 BCM_IF_ERROR_RETURN 3493 (_bcm_tr_cosq_resolve_mod_port(unit, input_gport, &input_modid, 3494 &input_port, &trunk_id)); 3495 3496 if (_tr_num_port_cosq[unit][sched_port] == 0) { 3497 /* GPORT has not been added. */ 3498 return BCM_E_NOT_FOUND; 3499 } else if ((sched_modid != input_modid) || (sched_port != input_port)) { 3500 /* Be sure the GPORT matches to the physical port */ 3501 return BCM_E_PARAM; 3502 } 3503 3504 BCM_IF_ERROR_RETURN 3505 (soc_reg_field32_modify(unit, ING_COS_MODEr, input_port, 3506 SELECTf, 0x3)); /* VLAN_COS */ 3507 BCM_IF_ERROR_RETURN 3508 (soc_reg_field32_modify(unit, COS_MODEr, input_port, 3509 SELECTf, 0x3)); /* VLAN_COS */ 3510 return BCM_E_NONE; 3511 } 3512 3513 /* 3514 * Function: 3515 * bcm_cosq_gport_detach 3516 * Purpose: 3517 * 3518 * Parameters: 3519 * unit - (IN) Unit number. 3520 * sched_port - (IN) Scheduler GPORT ID. 3521 * input_port - (IN) GPORT to detach from. 3522 * cosq - (IN) COS queue to detach from. 3523 * Returns: 3524 * BCM_E_XXX 3525 * Notes: 3526 */ 3527 int 3528 bcm_tr_cosq_gport_detach(int unit, bcm_gport_t sched_gport, 3529 bcm_gport_t input_gport, bcm_cos_queue_t cosq) 3530 { 3531 bcm_module_t sched_modid, input_modid; 3532 bcm_port_t sched_port, input_port; 3533 bcm_trunk_t trunk_id; 3534 3535 if (!BCM_GPORT_IS_SCHEDULER(sched_gport)) { 3536 return BCM_E_PORT; 3537 } else if (!_tr_num_port_cosq[unit]) { 3538 return BCM_E_INIT; 3539 } else if ((cosq > 0) && (cosq != TR_SCHEDULER_COSQ)) { 3540 return BCM_E_NOT_FOUND; 3541 } 3542 3543 BCM_IF_ERROR_RETURN 3544 (_bcm_tr_cosq_resolve_mod_port(unit, sched_gport, &sched_modid, 3545 &sched_port, &trunk_id)); 3546 BCM_IF_ERROR_RETURN 3547 (_bcm_tr_cosq_resolve_mod_port(unit, input_gport, &input_modid, 3548 &input_port, &trunk_id)); 3549 if (_tr_num_port_cosq[unit][sched_port] == 0) { 3550 /* GPORT has not been added. */ 3551 return BCM_E_NOT_FOUND; 3552 } else if ((sched_modid != input_modid) || (sched_port != input_port)) { 3553 /* Be sure the GPORT matches to the physical port */ 3554 return BCM_E_PORT; 3555 } 3556 3557 BCM_IF_ERROR_RETURN 3558 (soc_reg_field32_modify(unit, COS_MODEr, input_port, SELECTf, 0x0)); 3559 BCM_IF_ERROR_RETURN 3560 (soc_reg_field32_modify(unit, ING_COS_MODEr, input_port, SELECTf, 0x0)); 3561 return BCM_E_NONE; 3562 } 3563 3564 /* 3565 * Function: 3566 * bcm_cosq_gport_attach_get 3567 * Purpose: 3568 * 3569 * Parameters: 3570 * unit - (IN) Unit number. 3571 * sched_port - (IN) Scheduler GPORT ID. 3572 * input_port - (OUT) GPORT attached to. 3573 * cosq - (OUT) COS queue attached to. 3574 * Returns: 3575 * BCM_E_XXX 3576 * Notes: 3577 */ 3578 int 3579 bcm_tr_cosq_gport_attach_get(int unit, bcm_gport_t sched_gport, 3580 bcm_gport_t *input_gport, bcm_cos_queue_t *cosq) 3581 { 3582 bcm_module_t sched_modid, input_modid; 3583 bcm_port_t sched_port, input_port; 3584 bcm_trunk_t trunk_id; 3585 uint32 val; 3586 3587 if (!BCM_GPORT_IS_SCHEDULER(sched_gport) || 3588 !cosq || !input_gport) { 3589 return BCM_E_PARAM; 3590 } else if (!_tr_num_port_cosq[unit]) { 3591 return BCM_E_INIT; 3592 } 3593 3594 BCM_IF_ERROR_RETURN 3595 (_bcm_tr_cosq_resolve_mod_port(unit, sched_gport, &sched_modid, 3596 &sched_port, &trunk_id)); 3597 if (_tr_num_port_cosq[unit][sched_port] == 0) { 3598 /* GPORT has not been added. */ 3599 return BCM_E_NOT_FOUND; 3600 } 3601 3602 BCM_IF_ERROR_RETURN(READ_COS_MODEr(unit, sched_port, &val)); 3603 if (soc_reg_field_get(unit, COS_MODEr, val, SELECTf) == 3) { 3604 /* GPORT has been attached */ 3605 *cosq = TR_SCHEDULER_COSQ; 3606 3607 BCM_IF_ERROR_RETURN 3608 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET, 3609 sched_modid, sched_port, 3610 &input_modid, &input_port)); 3611 BCM_GPORT_MODPORT_SET(*input_gport, input_modid, input_port); 3612 } else { 3613 /* GPORT has not been attached */ 3614 return BCM_E_NOT_FOUND; 3615 } 3616 return BCM_E_NONE; 3617 } 3618 3619 #ifdef BCM_SCORPION_SUPPORT 3620 STATIC int 3621 _bcm_sc_cosq_discard_all_disable (int unit) 3622 { 3623 bcm_port_t port; 3624 bcm_cos_queue_t cosq; 3625 soc_reg_t config_reg; 3626 uint32 val, addr; 3627 3628 PBMP_ALL_ITER(unit, port) { 3629 if (IS_CPU_PORT(unit, port)) { 3630 continue; 3631 } 3632 /* Cosq level disabling */ 3633 config_reg = WREDCONFIG_CELLr; 3634 for (cosq = 0; cosq < 8; cosq++) { 3635 addr = soc_reg_addr(unit, config_reg, port, cosq); 3636 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &val)); 3637 soc_reg_field_set(unit, config_reg, &val, CAP_AVERAGEf, 0); 3638 soc_reg_field_set(unit, config_reg, &val, ENABLEf, 0); 3639 SOC_IF_ERROR_RETURN(soc_reg32_write(unit, addr, val)); 3640 } 3641 3642 /* Port level disabling */ 3643 config_reg = PORT_WREDCONFIG_CELLr; 3644 addr = soc_reg_addr(unit, config_reg, port, 0); 3645 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &val)); 3646 soc_reg_field_set(unit, config_reg, &val, CAP_AVERAGEf, 0); 3647 soc_reg_field_set(unit, config_reg, &val, ENABLEf, 0); 3648 SOC_IF_ERROR_RETURN(soc_reg32_write(unit, addr, val)); 3649 } 3650 3651 /* Chip level disabling */ 3652 config_reg = GLOBAL_WREDCONFIG_CELLr; 3653 addr = soc_reg_addr(unit, config_reg, REG_PORT_ANY, 0); 3654 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &val)); 3655 soc_reg_field_set(unit, config_reg, &val, CAP_AVERAGEf, 0); 3656 soc_reg_field_set(unit, config_reg, &val, ENABLEf, 0); 3657 SOC_IF_ERROR_RETURN(soc_reg32_write(unit, addr, val)); 3658 3659 return BCM_E_NONE; 3660 } 3661 3662 int 3663 bcm_sc_cosq_port_bandwidth_set(int unit, bcm_port_t port, 3664 bcm_cos_queue_t cosq, 3665 uint32 kbits_sec_min, 3666 uint32 kbits_sec_max, 3667 uint32 kbits_sec_burst, 3668 uint32 flags) 3669 { 3670 uint32 regval; 3671 uint32 bucket_val = 0; 3672 uint32 refresh_rate, bucketsize, granularity = 3, meter_flags = 0; 3673 int refresh_bitsize, bucket_bitsize; 3674 3675 3676 /* 3677 * To set the new Bandwidth settings, the procedure adopted is 3678 * a. reset MAXBUCKETCONFIG, MINBUCKETCONFIG, MAXBUCKET,MINBUCKET 3679 * b. update MAXBUCKETCONFIG and MINBUCKETCONFIG with new values passed 3680 * c. if MISCCONFIG.METERING_CLK_EN not set before, enable it. 3681 */ 3682 3683 BCM_IF_ERROR_RETURN(READ_MISCCONFIGr(unit, ®val)); 3684 if (soc_reg_field_get(unit, MISCCONFIGr, regval, ITU_MODE_SELf)) { 3685 meter_flags |= _BCM_XGS_METER_FLAG_NON_LINEAR; 3686 } 3687 meter_flags |= _BCM_XGS_METER_FLAG_GRANULARITY; 3688 3689 if (!IS_CPU_PORT(unit,port)) { 3690 /* Disable egress metering for this port */ 3691 BCM_IF_ERROR_RETURN(READ_MAXBUCKETCONFIG1r(unit, port, cosq, ®val)); 3692 soc_reg_field_set(unit, MAXBUCKETCONFIG1r, ®val, REFRESHf, 0); 3693 BCM_IF_ERROR_RETURN(WRITE_MAXBUCKETCONFIG1r(unit, port, cosq, regval)); 3694 3695 BCM_IF_ERROR_RETURN(READ_MAXBUCKETCONFIGr(unit, port, cosq, ®val)); 3696 soc_reg_field_set(unit, MAXBUCKETCONFIGr, ®val, THRESHOLDf, 0); 3697 BCM_IF_ERROR_RETURN(WRITE_MAXBUCKETCONFIGr(unit, port, cosq, regval)); 3698 } else { 3699 BCM_IF_ERROR_RETURN(READ_CPUPKTMAXBUCKETCONFIGr(unit, cosq, ®val)); 3700 soc_reg_field_set(unit, CPUPKTMAXBUCKETCONFIGr,®val, PKT_MAX_THD_SELf,0); 3701 soc_reg_field_set(unit, CPUPKTMAXBUCKETCONFIGr,®val, PKT_MAX_REFRESHf,0); 3702 BCM_IF_ERROR_RETURN(WRITE_CPUPKTMAXBUCKETCONFIGr(unit, cosq, regval)); 3703 } 3704 if (!IS_CPU_PORT(unit,port)) { 3705 BCM_IF_ERROR_RETURN(READ_MINBUCKETCONFIG1r(unit, port, cosq, ®val)); 3706 soc_reg_field_set(unit, MINBUCKETCONFIG1r, ®val, REFRESHf, 0); 3707 BCM_IF_ERROR_RETURN(WRITE_MINBUCKETCONFIG1r(unit, port, cosq, regval)); 3708 3709 BCM_IF_ERROR_RETURN(READ_MINBUCKETCONFIGr(unit, port, cosq, ®val)); 3710 soc_reg_field_set(unit, MINBUCKETCONFIGr, ®val, THRESHOLDf, 0); 3711 BCM_IF_ERROR_RETURN(WRITE_MINBUCKETCONFIGr(unit, port, cosq, regval)); 3712 /* Reset the MAXBUCKET register */ 3713 soc_reg_field_set(unit, MAXBUCKETr, &bucket_val, MAX_BUCKETf, 0); 3714 soc_reg_field_set(unit, MAXBUCKETr, &bucket_val, OUT_PROFILE_FLAGf, 0); 3715 BCM_IF_ERROR_RETURN(WRITE_MAXBUCKETr(unit, port, cosq, bucket_val)); 3716 3717 /*reset the MINBUCKET register value*/ 3718 soc_reg_field_set(unit, MINBUCKETr, &bucket_val, MIN_BUCKETf, 0); 3719 soc_reg_field_set(unit, MINBUCKETr, &bucket_val, OUT_PROFILE_FLAGf, 0); 3720 BCM_IF_ERROR_RETURN(WRITE_MINBUCKETr(unit, port, cosq, bucket_val)); 3721 3722 refresh_bitsize = 3723 soc_reg_field_length(unit, MINBUCKETCONFIG1r, REFRESHf); 3724 bucket_bitsize = 3725 soc_reg_field_length(unit, MINBUCKETCONFIGr, THRESHOLDf); 3726 BCM_IF_ERROR_RETURN 3727 (_bcm_xgs_kbits_to_bucket_encoding(kbits_sec_min, kbits_sec_min, 3728 meter_flags, refresh_bitsize, bucket_bitsize, 3729 &refresh_rate, &bucketsize, &granularity)); 3730 3731 regval = 0; 3732 soc_reg_field_set(unit, MINBUCKETCONFIGr, ®val, 3733 METER_GRANf, granularity); 3734 soc_reg_field_set(unit, MINBUCKETCONFIGr, 3735 ®val, THRESHOLDf, bucketsize); 3736 BCM_IF_ERROR_RETURN 3737 (WRITE_MINBUCKETCONFIGr(unit, port, cosq, regval)); 3738 3739 regval = 0; 3740 soc_reg_field_set(unit, MINBUCKETCONFIG1r, ®val, 3741 REFRESHf, refresh_rate); 3742 BCM_IF_ERROR_RETURN 3743 (WRITE_MINBUCKETCONFIG1r(unit, port, cosq, regval)); 3744 } 3745 3746 3747 if (!IS_CPU_PORT(unit,port)) { 3748 refresh_bitsize = 3749 soc_reg_field_length(unit, MAXBUCKETCONFIG1r, REFRESHf); 3750 bucket_bitsize = 3751 soc_reg_field_length(unit, MAXBUCKETCONFIGr, THRESHOLDf); 3752 } else { 3753 bucket_bitsize = soc_reg_field_length(unit, CPUPKTMAXBUCKETCONFIGr, 3754 PKT_MAX_THD_SELf); 3755 refresh_bitsize = soc_reg_field_length(unit, CPUPKTMAXBUCKETCONFIGr, 3756 PKT_MAX_REFRESHf); 3757 } 3758 BCM_IF_ERROR_RETURN 3759 (_bcm_xgs_kbits_to_bucket_encoding(kbits_sec_max, kbits_sec_burst, 3760 meter_flags, refresh_bitsize, bucket_bitsize, 3761 &refresh_rate, &bucketsize, &granularity)); 3762 3763 3764 if (!IS_CPU_PORT(unit,port)) { 3765 regval = 0; 3766 soc_reg_field_set(unit, MAXBUCKETCONFIGr, ®val, 3767 METER_GRANf, granularity); 3768 soc_reg_field_set(unit, MAXBUCKETCONFIGr, ®val, THRESHOLDf, 3769 bucketsize); 3770 BCM_IF_ERROR_RETURN(WRITE_MAXBUCKETCONFIGr(unit, port, cosq, regval)); 3771 3772 regval = 0; 3773 soc_reg_field_set(unit, MAXBUCKETCONFIG1r, ®val, 3774 REFRESHf, refresh_rate); 3775 BCM_IF_ERROR_RETURN(WRITE_MAXBUCKETCONFIG1r(unit, port, cosq, regval)); 3776 } else { 3777 regval = 0; 3778 soc_reg_field_set(unit, CPUPKTMAXBUCKETCONFIGr, ®val, PKT_MAX_THD_SELf, 3779 bucketsize); 3780 soc_reg_field_set(unit, CPUPKTMAXBUCKETCONFIGr, ®val, PKT_MAX_REFRESHf, 3781 refresh_rate); 3782 BCM_IF_ERROR_RETURN(WRITE_CPUPKTMAXBUCKETCONFIGr(unit, cosq, regval)); 3783 } 3784 3785 /* 10MISCCONFIG.METERING_CLK_EN is set by chip init */ 3786 return BCM_E_NONE; 3787 } 3788 3789 int 3790 bcm_sc_cosq_port_bandwidth_get(int unit, bcm_port_t port, 3791 bcm_cos_queue_t cosq, 3792 uint32 *kbits_sec_min, 3793 uint32 *kbits_sec_max, 3794 uint32 *kbits_sec_burst, 3795 uint32 *flags) 3796 { 3797 uint32 regval; 3798 uint32 refresh_rate = 0, bucketsize = 0, 3799 granularity = 3, meter_flags = 0; 3800 uint32 kbits_min_burst; /* Placeholder, since burst is unused for min */ 3801 3802 if (!kbits_sec_min || !kbits_sec_max || !kbits_sec_burst || !flags) { 3803 return (BCM_E_PARAM); 3804 } 3805 3806 BCM_IF_ERROR_RETURN(READ_MISCCONFIGr(unit, ®val)); 3807 if (soc_reg_field_get(unit, MISCCONFIGr, regval, ITU_MODE_SELf)) { 3808 meter_flags |= _BCM_XGS_METER_FLAG_NON_LINEAR; 3809 } 3810 3811 if (!IS_CPU_PORT(unit,port)) { 3812 meter_flags |= _BCM_XGS_METER_FLAG_GRANULARITY; 3813 BCM_IF_ERROR_RETURN(READ_MAXBUCKETCONFIGr(unit, port, cosq, ®val)); 3814 granularity = soc_reg_field_get(unit, MAXBUCKETCONFIGr, 3815 regval, METER_GRANf); 3816 bucketsize = soc_reg_field_get(unit, MAXBUCKETCONFIGr, 3817 regval, THRESHOLDf); 3818 BCM_IF_ERROR_RETURN(READ_MAXBUCKETCONFIG1r(unit, port, cosq, ®val)); 3819 refresh_rate = soc_reg_field_get(unit, MAXBUCKETCONFIG1r, 3820 regval, REFRESHf); 3821 } else { 3822 BCM_IF_ERROR_RETURN(READ_CPUPKTMAXBUCKETCONFIGr(unit, cosq, ®val)); 3823 bucketsize = soc_reg_field_get(unit, CPUPKTMAXBUCKETCONFIGr, 3824 regval, PKT_MAX_THD_SELf); 3825 refresh_rate = soc_reg_field_get(unit, CPUPKTMAXBUCKETCONFIGr, 3826 regval, PKT_MAX_REFRESHf); 3827 } 3828 3829 BCM_IF_ERROR_RETURN 3830 (_bcm_xgs_bucket_encoding_to_kbits(refresh_rate, bucketsize, 3831 granularity, meter_flags, 3832 kbits_sec_max, kbits_sec_burst)); 3833 3834 if (!IS_CPU_PORT(unit,port)) { 3835 BCM_IF_ERROR_RETURN(READ_MINBUCKETCONFIGr(unit, port, cosq, ®val)); 3836 granularity = soc_reg_field_get(unit, MINBUCKETCONFIGr, 3837 regval, METER_GRANf); 3838 BCM_IF_ERROR_RETURN(READ_MINBUCKETCONFIG1r(unit, port, cosq, ®val)); 3839 refresh_rate = soc_reg_field_get(unit, MINBUCKETCONFIG1r, 3840 regval, REFRESHf); 3841 } 3842 3843 BCM_IF_ERROR_RETURN 3844 (_bcm_xgs_bucket_encoding_to_kbits(refresh_rate, 0, 3845 granularity, meter_flags, 3846 kbits_sec_min, &kbits_min_burst)); 3847 3848 *flags = 0; 3849 3850 return BCM_E_NONE; 3851 } 3852 3853 int 3854 bcm_sc_cosq_discard_set(int unit, uint32 flags) 3855 { 3856 bcm_port_t port; 3857 bcm_cos_queue_t cosq; 3858 soc_reg_t config_reg = WREDCONFIG_CELLr; 3859 3860 PBMP_ALL_ITER(unit, port) { 3861 if (IS_CPU_PORT(unit, port)) { 3862 continue; 3863 } 3864 for (cosq = 0; cosq < 8; cosq++) { 3865 BCM_IF_ERROR_RETURN 3866 (_bcm_tr_cosq_discard_cap_enable_set(unit, port, cosq, 3867 config_reg, flags)); 3868 } 3869 } 3870 return BCM_E_NONE; 3871 } 3872 3873 int 3874 bcm_sc_cosq_discard_get(int unit, uint32 *flags) 3875 { 3876 int rv = BCM_E_NONE; 3877 bcm_port_t port; 3878 soc_reg_t config_reg = WREDCONFIG_CELLr; 3879 3880 PBMP_ALL_ITER(unit, port) { 3881 if (IS_CPU_PORT(unit, port)) { 3882 continue; 3883 } 3884 *flags = 0; 3885 rv = _bcm_tr_cosq_discard_cap_enable_get(unit, port, 0, 3886 config_reg, flags); 3887 break; 3888 } 3889 return rv; 3890 } 3891 3892 int 3893 bcm_sc_cosq_discard_port_set(int unit, bcm_port_t port, 3894 bcm_cos_queue_t cosq, 3895 uint32 color, 3896 int drop_start, 3897 int drop_slope, 3898 int average_time) 3899 { 3900 bcm_module_t modid; 3901 bcm_port_t local_port; 3902 bcm_trunk_t trunk_id; 3903 bcm_pbmp_t pbmp; 3904 _bcm_gport_dest_t dest; 3905 bcm_gport_t gport; 3906 int i, cosq_start, num_cosq; 3907 uint32 shared_limit; 3908 uint32 rval, bits; 3909 bcm_cosq_gport_discard_t discard; 3910 3911 if (!_tr_num_cosq[unit]) { 3912 return BCM_E_INIT; 3913 } 3914 3915 if (drop_start < 0 || drop_start > 100 || 3916 drop_slope < 0 || drop_slope > 90) { 3917 return BCM_E_PARAM; 3918 } 3919 3920 if (BCM_GPORT_IS_SET(port)) { 3921 BCM_IF_ERROR_RETURN 3922 (_bcm_tr_cosq_resolve_mod_port(unit, port, &modid, 3923 &local_port, &trunk_id)); 3924 BCM_PBMP_PORT_SET(pbmp, local_port); 3925 } else { 3926 if (port == -1) { 3927 BCM_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit)); 3928 } else if (!SOC_PORT_VALID(unit, port)) { 3929 return BCM_E_PORT; 3930 } else { 3931 BCM_PBMP_PORT_SET(pbmp, port); 3932 } 3933 } 3934 3935 if (cosq < -1 || cosq >= _tr_num_cosq[unit]) { 3936 return BCM_E_PARAM; 3937 } else if (cosq == -1) { 3938 cosq_start = 0; 3939 num_cosq = _tr_num_cosq[unit]; 3940 } else { 3941 cosq_start = cosq; 3942 num_cosq = 1; 3943 } 3944 3945 /* Init structure */ 3946 bcm_cosq_gport_discard_t_init(&discard); 3947 3948 /* BCM_COSQ_DISCARD_ENABLE & BCM_COSQ_DISCARD_CAP_AVERAGE 3949 * from current state */ 3950 bcm_sc_cosq_discard_get(unit, &(discard.flags)); 3951 3952 discard.flags |= color; 3953 3954 /* 3955 * average queue size is reculated every 4us, the formula is 3956 * avg_qsize(t + 1) = 3957 * avg_qsize(t) + (cur_qsize - avg_qsize(t)) / (2 ** gain) 3958 * gain = log2(average_time / 4) 3959 */ 3960 bits = (average_time / 4) & 0xffff; 3961 bits |= bits >> 1; 3962 bits |= bits >> 2; 3963 bits |= bits >> 4; 3964 bits |= bits >> 8; 3965 discard.gain = _shr_popcount(bits); 3966 /* Don't alow negative value of gain */ 3967 if (discard.gain) { 3968 discard.gain -= 1; 3969 } 3970 3971 /* 3972 * per-port cell limit may be disabled. 3973 * per-port per-cos cell limit may be set to use dynamic method. 3974 * therefore drop_start percentage is based on per-device total shared 3975 * cells. 3976 */ 3977 SOC_IF_ERROR_RETURN(READ_OP_BUFFER_SHARED_LIMITr(unit, &rval)); 3978 shared_limit = soc_reg_field_get(unit, OP_BUFFER_SHARED_LIMITr, 3979 rval, OP_BUFFER_SHARED_LIMITf); 3980 discard.min_thresh = drop_start * shared_limit / 100; 3981 3982 /* Calculate the max threshold. For a given slope (angle in 3983 * degrees), determine how many cells are in the range from 3984 * 0% drop probability to 100% drop probability. Add that 3985 * number to the min_threshold for the the max_threshold. 3986 */ 3987 3988 /* Because SC_CELL_FIELD_MAX == TR_PACKET_FIELD_MAX(unit), 3989 * we can use the TR packet converter as our cell converter */ 3990 discard.max_thresh = discard.min_thresh + 3991 _bcm_tr_angle_to_packets(drop_slope); 3992 if (discard.max_thresh > SC_CELL_FIELD_MAX) { 3993 discard.max_thresh = SC_CELL_FIELD_MAX; 3994 } 3995 3996 /* Put thresholds in units of bytes */ 3997 discard.min_thresh *= _BCM_TR_COSQ_CELLSIZE; 3998 discard.max_thresh *= _BCM_TR_COSQ_CELLSIZE; 3999 discard.flags |= BCM_COSQ_DISCARD_BYTES; 4000 4001 /* We use drop probabily of 1 here. Use bcm_cosq_gport_discard_set 4002 * for more flexibility. */ 4003 discard.drop_probability = 100; 4004 4005 BCM_PBMP_ITER(pbmp, local_port) { 4006 _bcm_gport_dest_t_init(&dest); 4007 dest.port = local_port; 4008 dest.gport_type = _SHR_GPORT_TYPE_LOCAL; 4009 BCM_IF_ERROR_RETURN(_bcm_esw_gport_construct(unit, &dest, &gport)); 4010 for (i = cosq_start; i < (cosq_start + num_cosq); i++) { 4011 BCM_IF_ERROR_RETURN 4012 (bcm_tr_cosq_gport_discard_set(unit, gport, i, &discard)); 4013 } 4014 } 4015 return BCM_E_NONE; 4016 } 4017 4018 int 4019 bcm_sc_cosq_discard_port_get(int unit, bcm_port_t port, 4020 bcm_cos_queue_t cosq, 4021 uint32 color, 4022 int *drop_start, 4023 int *drop_slope, 4024 int *average_time) 4025 { 4026 bcm_module_t modid; 4027 bcm_port_t local_port; 4028 bcm_trunk_t trunk_id; 4029 bcm_pbmp_t pbmp; 4030 _bcm_gport_dest_t dest; 4031 bcm_gport_t gport; 4032 uint32 min_thresh, max_thresh, shared_limit; 4033 uint32 rval; 4034 bcm_cosq_gport_discard_t discard; 4035 4036 if (!_tr_num_cosq[unit]) { 4037 return BCM_E_INIT; 4038 } 4039 4040 if (drop_start == NULL || drop_slope == NULL || average_time == NULL) { 4041 return BCM_E_PARAM; 4042 } 4043 4044 if (BCM_GPORT_IS_SET(port)) { 4045 BCM_IF_ERROR_RETURN 4046 (_bcm_tr_cosq_resolve_mod_port(unit, port, &modid, 4047 &local_port, &trunk_id)); 4048 BCM_PBMP_PORT_SET(pbmp, local_port); 4049 } else { 4050 if (port == -1) { 4051 BCM_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit)); 4052 } else if (!SOC_PORT_VALID(unit, port)) { 4053 return BCM_E_PORT; 4054 } else { 4055 BCM_PBMP_PORT_SET(pbmp, port); 4056 } 4057 } 4058 4059 if (cosq < -1 || cosq >= _tr_num_cosq[unit]) { 4060 return BCM_E_PARAM; 4061 } else if (cosq == -1) { 4062 cosq = 0; 4063 } 4064 4065 BCM_PBMP_ITER(pbmp, local_port) { 4066 _bcm_gport_dest_t_init(&dest); 4067 dest.port = local_port; 4068 dest.gport_type = _SHR_GPORT_TYPE_LOCAL; 4069 BCM_IF_ERROR_RETURN(_bcm_esw_gport_construct(unit, &dest, &gport)); 4070 4071 /* Init structure */ 4072 bcm_cosq_gport_discard_t_init(&discard); 4073 4074 /* Prepare input flags */ 4075 /* Convert color to flags */ 4076 discard.flags |= color; 4077 discard.flags |= BCM_COSQ_DISCARD_BYTES; 4078 4079 BCM_IF_ERROR_RETURN 4080 (bcm_tr_cosq_gport_discard_get(unit, gport, cosq, &discard)); 4081 4082 /* 4083 * average queue size is reculated every 4us, the formula is 4084 * avg_qsize(t + 1) = 4085 * avg_qsize(t) + (cur_qsize - avg_qsize(t)) / (2 ** gain) 4086 */ 4087 *average_time = (1 << discard.gain) * 4; 4088 4089 /* Change bytes to cells for the following calculations */ 4090 min_thresh = discard.min_thresh / _BCM_SC_COSQ_CELLSIZE; 4091 max_thresh = discard.max_thresh / _BCM_SC_COSQ_CELLSIZE; 4092 4093 /* 4094 * per-port cell limit may be disabled. 4095 * per-port per-cos cell limit may be set to use dynamic method. 4096 * therefore drop_start percentage is based on per-device total shared 4097 * cells. 4098 */ 4099 SOC_IF_ERROR_RETURN(READ_OP_BUFFER_SHARED_LIMITr(unit, &rval)); 4100 shared_limit = soc_reg_field_get(unit, OP_BUFFER_SHARED_LIMITr, 4101 rval, OP_BUFFER_SHARED_LIMITf); 4102 *drop_start = min_thresh * 100 / shared_limit; 4103 4104 /* Calculate the slope using the min and max threshold. 4105 * The angle is calculated knowing drop probability at min 4106 * threshold is 0% and drop probability at max threshold is 100%. 4107 */ 4108 *drop_slope = _bcm_tr_packets_to_angle(max_thresh - min_thresh); 4109 break; 4110 } 4111 4112 return BCM_E_NONE; 4113 } 4114 4115 /* 4116 * Function: 4117 * bcm_sc_cosq_gport_sched_set 4118 * Purpose: 4119 * 4120 * Parameters: 4121 * unit - (IN) Unit number. 4122 * gport - (IN) GPORT ID. 4123 * cosq - (IN) COS queue to configure, -1 for all COS queues. 4124 * mode - (IN) Scheduling mode, one of BCM_COSQ_xxx 4125 * weight - (IN) Weight for the specified COS queue(s) 4126 * Unused if mode is BCM_COSQ_STRICT. 4127 * Returns: 4128 * BCM_E_XXX 4129 */ 4130 int 4131 bcm_sc_cosq_gport_sched_set(int unit, bcm_gport_t gport, 4132 bcm_cos_queue_t cosq, int mode, int weight) 4133 { 4134 bcm_module_t modid; 4135 bcm_port_t local_port; 4136 bcm_trunk_t trunk_id; 4137 int i; 4138 bcm_cos_queue_t cosq_start = 0; 4139 int num_weights = 1, weights[16]; 4140 4141 /* Note, we use the TR functions here, but they work for Scorpion */ 4142 BCM_IF_ERROR_RETURN 4143 (_bcm_tr_cosq_resolve_mod_port(unit, gport, &modid, 4144 &local_port, &trunk_id)); 4145 4146 if (cosq >= _tr_num_cosq[unit]) { 4147 return BCM_E_PARAM; 4148 } else if (cosq < 0) { 4149 cosq_start = 0; 4150 num_weights = 8; 4151 for (i = 0; i < num_weights; i++) { 4152 if (i < _tr_num_cosq[unit]) { 4153 weights[i] = weight; 4154 } else { 4155 weights[i] = 0; 4156 } 4157 } 4158 } else { 4159 cosq_start = cosq; 4160 num_weights = 1; 4161 weights[0] = weight; 4162 } 4163 4164 BCM_IF_ERROR_RETURN 4165 (_bcm_tr_cosq_port_sched_set(unit, ESCONFIGr, COSWEIGHTSr, 4166 MINSPCONFIGr, local_port, 4167 cosq_start, num_weights, 4168 weights, mode)); 4169 return BCM_E_NONE; 4170 } 4171 4172 /* 4173 * Function: 4174 * bcm_sc_cosq_gport_sched_get 4175 * Purpose: 4176 * 4177 * Parameters: 4178 * unit - (IN) Unit number. 4179 * gport - (IN) GPORT ID. 4180 * cosq - (IN) COS queue 4181 * mode - (OUT) Scheduling mode, one of BCM_COSQ_xxx 4182 * weight - (OUT) Weight for the specified COS queue(s) 4183 * Unused if mode is BCM_COSQ_STRICT. 4184 * Returns: 4185 * BCM_E_XXX 4186 */ 4187 int 4188 bcm_sc_cosq_gport_sched_get(int unit, bcm_gport_t gport, 4189 bcm_cos_queue_t cosq, int *mode, int *weight) 4190 { 4191 bcm_module_t modid; 4192 bcm_port_t local_port; 4193 bcm_trunk_t trunk_id; 4194 4195 *mode = *weight = 0; 4196 4197 /* Note, we use the TR functions here, but they work for Scorpion */ 4198 BCM_IF_ERROR_RETURN 4199 (_bcm_tr_cosq_resolve_mod_port(unit, gport, &modid, 4200 &local_port, &trunk_id)); 4201 if (cosq >= _tr_num_cosq[unit]) { 4202 return BCM_E_PARAM; 4203 } else if (cosq < 0) { 4204 cosq = 0; 4205 } 4206 BCM_IF_ERROR_RETURN 4207 (_bcm_tr_cosq_port_sched_get(unit, ESCONFIGr, COSWEIGHTSr, 4208 local_port, cosq, 1, 4209 weight, mode)); 4210 return BCM_E_NONE; 4211 } 4212 4213 #endif /* BCM_SCORPION_SUPPORT */ 4214 4215 #ifndef BCM_SW_STATE_DUMP_DISABLE 4216 /* 4217 * Function: 4218 * bcm_tr_cosq_sw_dump 4219 * Purpose: 4220 * Displays COS Queue information maintained by software. 4221 * Parameters: 4222 * unit - Device unit number 4223 * Returns: 4224 * None 4225 */ 4226 void 4227 bcm_tr_cosq_sw_dump(int unit) 4228 { 4229 int i; 4230 int port_count; 4231 4232 LOG_CLI((BSL_META_U(unit, 4233 "\nSW Information COSQ - Unit %d\n"), unit)); 4234 4235 /* Number COSQ */ 4236 LOG_CLI((BSL_META_U(unit, 4237 " Number: %d\n"), _tr_num_cosq[unit])); 4238 4239 /* Number of COSQs per port */ 4240 port_count = _bcm_tr_cosq_port_count_get(unit); 4241 LOG_CLI((BSL_META_U(unit, 4242 " Number COSQ per port:\n"))); 4243 if (_tr_num_port_cosq[unit] != NULL) { 4244 for (i = 0; i < port_count; i++) { 4245 LOG_CLI((BSL_META_U(unit, 4246 " Port %2d: %d\n"), i, 4247 _tr_num_port_cosq[unit][i])); 4248 } 4249 } 4250 4251 /* COSQ Map profile */ 4252 /* Display those entries with reference count > 0 */ 4253 LOG_CLI((BSL_META_U(unit, 4254 " COSQ Map Profile:\n"))); 4255 if (_tr_cos_map_profile[unit] != NULL) { 4256 int num_entries; 4257 int ref_count; 4258 int entries_per_set; 4259 uint32 index; 4260 port_cos_map_entry_t *entry_p; 4261 uint32 cosq, hg_cosq; 4262 4263 num_entries = soc_mem_index_count 4264 (unit, _tr_cos_map_profile[unit]->tables[0].mem); 4265 LOG_CLI((BSL_META_U(unit, 4266 " Number of entries: %d\n"), num_entries)); 4267 LOG_CLI((BSL_META_U(unit, 4268 " Index RefCount EntriesPerSet - " 4269 "COS HG_COS\n"))); 4270 4271 for (index = 0; index < num_entries; 4272 index += TR_COS_MAP_ENTRIES_PER_SET) { 4273 if (SOC_FAILURE 4274 (soc_profile_mem_ref_count_get(unit, 4275 _tr_cos_map_profile[unit], 4276 index, &ref_count))) { 4277 break; 4278 } 4279 4280 if (ref_count <= 0) { 4281 continue; 4282 } 4283 4284 for (i = 0; i < TR_COS_MAP_ENTRIES_PER_SET; i++) { 4285 entries_per_set = 4286 _tr_cos_map_profile[unit]->tables[0].entries[index+i].entries_per_set; 4287 LOG_CLI((BSL_META_U(unit, 4288 " %5d %8d %13d "), 4289 index + i, ref_count, entries_per_set)); 4290 4291 entry_p = SOC_PROFILE_MEM_ENTRY(unit, 4292 _tr_cos_map_profile[unit], 4293 port_cos_map_entry_t *, 4294 index + i); 4295 cosq = soc_mem_field32_get(unit, 4296 PORT_COS_MAPm, 4297 entry_p, 4298 COSf); 4299 LOG_CLI((BSL_META_U(unit, 4300 "%2d "), cosq)); 4301 if (soc_mem_field_valid(unit, PORT_COS_MAPm, HG_COSf)) { 4302 hg_cosq = soc_mem_field32_get(unit, PORT_COS_MAPm, 4303 entry_p, 4304 HG_COSf); 4305 LOG_CLI((BSL_META_U(unit, 4306 " %2d"), hg_cosq)); 4307 } 4308 LOG_CLI((BSL_META_U(unit, 4309 "\n"))); 4310 } 4311 } 4312 } 4313 4314 return; 4315 } 4316 #endif /* BCM_SW_STATE_DUMP_DISABLE */ 4317 4318 #else /* BCM_TRX_SUPPORT */ 4319 int _tr_cosq_not_empty; 4320 #endif /* BCM_TRX_SUPPORT */ 4321