cosq.c (121039B)
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_TRIUMPH2_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/triumph2.h> 26 #include <bcm_int/esw/stack.h> 27 28 #include <bcm_int/esw_dispatch.h> 29 30 #ifdef BCM_WARM_BOOT_SUPPORT 31 #include <bcm_int/esw/switch.h> 32 #endif /* BCM_WARM_BOOT_SUPPORT */ 33 34 #define TR2_DRR_WEIGHT_MAX 0x7f 35 #define TR2_WRR_WEIGHT_MAX 0x7f 36 37 #define TR2_PACKET_FIELD_MAX 0x3fff 38 #define TR2_CELL_FIELD_MAX 0x7fff 39 40 #define TR2_PKT_REFRESH_MAX 0xfffff 41 #define TR2_PKT_THD_MAX 0x7ff 42 43 /* COSQ where output of hierarchical COSQs scheduler is attached */ 44 #define TR2_SCHEDULER_COSQ 8 45 46 /* MMU cell size in bytes */ 47 #define _BCM_TR2_COSQ_CELLSIZE 128 48 49 /* Number of ports */ 50 #define TR2_PORT_COUNT 52 51 52 /* COS Map profile entries per set */ 53 #define TR2_COS_MAP_ENTRIES_PER_SET 16 54 55 /* Cache of COS_MAP Profile Table */ 56 STATIC soc_profile_mem_t *_tr2_cos_map_profile[BCM_MAX_NUM_UNITS] = {NULL}; 57 /* Cache of COS_EGR_MAP Profile Table */ 58 STATIC soc_profile_mem_t *_tr2_cos_egr_map_profile[BCM_MAX_NUM_UNITS] = {NULL}; 59 60 /* Number of COSQs configured for this device */ 61 STATIC int _tr2_num_cosq[SOC_MAX_NUM_DEVICES]; 62 63 /* Port Bitmap which includes ports capable of hierarchical queueing */ 64 STATIC soc_pbmp_t _tr2_cosq_24q_ports[SOC_MAX_NUM_DEVICES]; 65 66 /* Array to keep track of the number of hierarchical COSQs added per port */ 67 STATIC uint8 *_tr2_num_port_cosq[SOC_MAX_NUM_DEVICES] = {NULL}; 68 69 /* Forward declarations */ 70 STATIC int _bcm_tr2_cosq_gport_delete(int unit, bcm_port_t port); 71 STATIC int _bcm_tr2_cosq_port_sched_set(int unit, soc_reg_t config_reg, 72 soc_reg_t weight_reg, soc_reg_t minsp_reg, 73 bcm_port_t port, bcm_cos_queue_t start_cosq, 74 int num_weights, const int weights[], 75 int mode); 76 STATIC int _bcm_tr2_cosq_discard_set(int unit, bcm_port_t port, uint32 flags, 77 bcm_cos_queue_t cosq, soc_reg_t config_reg, 78 soc_reg_t thresh_reg_green, 79 soc_reg_t thresh_reg_yellow, 80 soc_reg_t thresh_reg_red, 81 soc_reg_t thresh_reg_non_tcp, 82 uint32 min_thresh, uint32 max_thresh, 83 int drop_probability, int gain); 84 85 86 /* 87 * Function: 88 * _bcm_tr2_egr_cpu_cos_map 89 * Purpose: 90 * Set the initial one to one mapping for he EGR_CPU_COS_MAP table 91 * Parameters: 92 * unit - Unit number. 93 * numq - Number of cosq provided 94 * Returns: 95 * BCM_E_XXX 96 */ 97 STATIC int 98 _bcm_tr2_egr_cpu_cos_map(int unit, int numq) 99 { 100 int i, imin, imax, bytes, nent, rv; 101 egr_cpu_cos_map_entry_t *entblk, *entryp; 102 int cos, ratio, remain; 103 104 imin = soc_mem_index_min(unit, EGR_CPU_COS_MAPm); 105 imax = soc_mem_index_max(unit, EGR_CPU_COS_MAPm); 106 nent = soc_mem_index_count(unit, EGR_CPU_COS_MAPm); 107 bytes = soc_mem_entry_words(unit, EGR_CPU_COS_MAPm); 108 bytes = WORDS2BYTES(bytes); 109 entblk = soc_cm_salloc(unit, nent * sizeof(egr_cpu_cos_map_entry_t), 110 "EGR_CPU_COS_MAP"); 111 if (entblk == NULL) { 112 return BCM_E_MEMORY; 113 } 114 115 soc_mem_lock(unit, EGR_CPU_COS_MAPm); 116 rv = soc_mem_read_range(unit, EGR_CPU_COS_MAPm, MEM_BLOCK_ANY, 117 imin, imax, entblk); 118 if (BCM_FAILURE(rv)) { 119 soc_mem_unlock(unit, EGR_CPU_COS_MAPm); 120 soc_cm_sfree(unit, entblk); 121 return rv; 122 } 123 124 ratio = nent / numq; 125 remain = nent % numq; 126 127 cos = 0; 128 for(i = 0; i < nent; i++) { 129 entryp = soc_mem_table_idx_to_pointer(unit, EGR_CPU_COS_MAPm, 130 egr_cpu_cos_map_entry_t *, entblk, i); 131 132 soc_mem_field32_set(unit, EGR_CPU_COS_MAPm, (uint32 *) entryp, 133 REDIRECT_COSf, cos); 134 135 if ((i + 1) == (((cos + 1) * ratio) + 136 ((remain < (numq - cos)) ? 0 : 137 (remain - (numq - cos) + 1)))) { 138 cos++; 139 } 140 141 } 142 143 rv = soc_mem_write_range(unit, EGR_CPU_COS_MAPm, MEM_BLOCK_ALL, 144 imin, imax, entblk); 145 soc_mem_unlock(unit, EGR_CPU_COS_MAPm); 146 soc_cm_sfree(unit, entblk); 147 148 return rv; 149 } 150 151 #ifdef BCM_WARM_BOOT_SUPPORT 152 153 #define BCM_WB_VERSION_1_0 SOC_SCACHE_VERSION(1,0) 154 #define BCM_WB_DEFAULT_VERSION BCM_WB_VERSION_1_0 155 156 /* 157 * Function: 158 * bcm_tr2_cosq_sync 159 * Purpose: 160 * Record COSQ module persistent info for Level 2 Warm Boot. 161 * Parameters: 162 * unit - Unit number. 163 * Returns: 164 * BCM_E_XXX 165 */ 166 int 167 bcm_tr2_cosq_sync(int unit) 168 { 169 soc_scache_handle_t scache_handle; 170 uint8 *cosq_scache_ptr; 171 uint32 num_cosq; 172 173 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 0); 174 BCM_IF_ERROR_RETURN 175 (_bcm_esw_scache_ptr_get(unit, scache_handle, FALSE, 176 0, &cosq_scache_ptr, 177 BCM_WB_DEFAULT_VERSION, NULL)); 178 179 /* Number COSQ */ 180 num_cosq = _tr2_num_cosq[unit]; 181 sal_memcpy(cosq_scache_ptr, &num_cosq, sizeof(num_cosq)); 182 cosq_scache_ptr += sizeof(num_cosq); 183 184 /* Number of hierarchical COSQs added per port */ 185 if (_tr2_num_port_cosq[unit] != NULL) { 186 sal_memcpy(cosq_scache_ptr, _tr2_num_port_cosq[unit], 187 sizeof(uint8) * TR2_PORT_COUNT); 188 } 189 190 return BCM_E_NONE; 191 } 192 193 /* 194 * Function: 195 * _bcm_tr2_cosq_reinit 196 * Purpose: 197 * Recover COSQ software state. 198 * Parameters: 199 * unit - Unit number. 200 * Returns: 201 * BCM_E_XXX 202 */ 203 STATIC int 204 _bcm_tr2_cosq_reinit(int unit) 205 { 206 int rv; 207 soc_scache_handle_t scache_handle; 208 uint8 *cosq_scache_ptr; 209 uint32 num_cosq; 210 211 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 0); 212 rv = _bcm_esw_scache_ptr_get(unit, scache_handle, FALSE, 213 0, &cosq_scache_ptr, 214 BCM_WB_DEFAULT_VERSION, NULL); 215 216 if (rv == BCM_E_NOT_FOUND) { 217 cosq_scache_ptr = NULL; 218 } else if (BCM_FAILURE(rv)) { 219 return rv; 220 } 221 222 if (cosq_scache_ptr != NULL) { 223 /* Number COSQ */ 224 sal_memcpy(&num_cosq, cosq_scache_ptr, sizeof(num_cosq)); 225 _tr2_num_cosq[unit] = num_cosq; 226 cosq_scache_ptr += sizeof(num_cosq); 227 228 /* Number of hierarchical COSQs added per port */ 229 if (_tr2_num_port_cosq[unit] != NULL) { 230 sal_memcpy(_tr2_num_port_cosq[unit], cosq_scache_ptr, 231 sizeof(uint8) * TR2_PORT_COUNT); 232 } 233 234 } else { 235 _tr2_num_cosq[unit] = _bcm_esw_cosq_config_property_get(unit); 236 } 237 238 return BCM_E_NONE; 239 } 240 #endif /* BCM_WARM_BOOT_SUPPORT */ 241 242 /* 243 * Function: 244 * bcm_cosq_init 245 * Purpose: 246 * Initialize (clear) all COS schedule/mapping state. 247 * Parameters: 248 * unit - StrataSwitch unit number. 249 * Returns: 250 * BCM_E_XXX 251 */ 252 253 int 254 bcm_tr2_cosq_init(int unit) 255 { 256 STATIC int _tr2_max_cosq = -1; 257 int num_cos; 258 #ifdef BCM_WARM_BOOT_SUPPORT 259 int rv; 260 soc_scache_handle_t scache_handle; 261 uint32 cosq_scache_size; 262 uint8 *cosq_scache_ptr; 263 #endif /* BCM_WARM_BOOT_SUPPORT */ 264 265 if (_tr2_max_cosq < 0) { 266 _tr2_max_cosq = NUM_COS(unit); 267 NUM_COS(unit) = 8; 268 } 269 270 if (!SOC_WARM_BOOT(unit)) { /* Cold Boot */ 271 BCM_IF_ERROR_RETURN (bcm_tr2_cosq_detach(unit, 0)); 272 } 273 274 num_cos = _bcm_esw_cosq_config_property_get(unit); 275 276 SOC_PBMP_CLEAR(_tr2_cosq_24q_ports[unit]); 277 /* Keep track of ports that support 24 (16 + 8) queues */ 278 SOC_PBMP_PORT_ADD(_tr2_cosq_24q_ports[unit], 26); 279 SOC_PBMP_PORT_ADD(_tr2_cosq_24q_ports[unit], 27); 280 SOC_PBMP_PORT_ADD(_tr2_cosq_24q_ports[unit], 28); 281 SOC_PBMP_PORT_ADD(_tr2_cosq_24q_ports[unit], 29); 282 SOC_PBMP_PORT_ADD(_tr2_cosq_24q_ports[unit], 30); 283 SOC_PBMP_PORT_ADD(_tr2_cosq_24q_ports[unit], 31); 284 SOC_PBMP_PORT_ADD(_tr2_cosq_24q_ports[unit], 34); 285 SOC_PBMP_PORT_ADD(_tr2_cosq_24q_ports[unit], 38); 286 SOC_PBMP_PORT_ADD(_tr2_cosq_24q_ports[unit], 39); 287 SOC_PBMP_PORT_ADD(_tr2_cosq_24q_ports[unit], 42); 288 SOC_PBMP_PORT_ADD(_tr2_cosq_24q_ports[unit], 43); 289 SOC_PBMP_PORT_ADD(_tr2_cosq_24q_ports[unit], 46); 290 SOC_PBMP_PORT_ADD(_tr2_cosq_24q_ports[unit], 50); 291 SOC_PBMP_PORT_ADD(_tr2_cosq_24q_ports[unit], 51); 292 if (_tr2_num_port_cosq[unit] == NULL) { 293 _tr2_num_port_cosq[unit] = sal_alloc(sizeof(uint8) * TR2_PORT_COUNT, 294 "_tr2_num_port_cosq"); 295 if (_tr2_num_port_cosq[unit] == NULL) { 296 return BCM_E_MEMORY; 297 } 298 } 299 sal_memset(_tr2_num_port_cosq[unit], 0, sizeof(uint8) * TR2_PORT_COUNT); 300 301 #ifdef BCM_WARM_BOOT_SUPPORT 302 /* Warm boot level 2 cache size */ 303 cosq_scache_size = sizeof(uint32); /* Number COSQ */ 304 if (_tr2_num_port_cosq[unit] != NULL) { /* Number of COSQs per port */ 305 cosq_scache_size += (sizeof(uint8) * TR2_PORT_COUNT); 306 } 307 308 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 0); 309 rv = _bcm_esw_scache_ptr_get(unit, scache_handle, 310 (0 == SOC_WARM_BOOT(unit)), 311 cosq_scache_size, &cosq_scache_ptr, 312 BCM_WB_DEFAULT_VERSION, NULL); 313 if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) { 314 return rv; 315 } 316 317 if (SOC_WARM_BOOT(unit)) { 318 BCM_IF_ERROR_RETURN(_bcm_tr2_cosq_reinit(unit)); 319 num_cos = _tr2_num_cosq[unit]; 320 } 321 #endif /* BCM_WARM_BOOT_SUPPORT */ 322 323 return bcm_tr2_cosq_config_set(unit, num_cos); 324 } 325 326 /* 327 * Function: 328 * bcm_cosq_detach 329 * Purpose: 330 * Discard all COS schedule/mapping state. 331 * Parameters: 332 * unit - StrataSwitch unit number. 333 * Returns: 334 * BCM_E_XXX 335 */ 336 337 int 338 bcm_tr2_cosq_detach(int unit, int software_state_only) 339 { 340 bcm_port_t port; 341 int weights[8]; 342 int cosq; 343 344 /* Delete any gports that were added */ 345 if (_tr2_num_port_cosq[unit]) { 346 BCM_PBMP_ITER(_tr2_cosq_24q_ports[unit], port) { 347 if (_tr2_num_port_cosq[unit][port]) 348 { 349 if (!software_state_only) 350 { 351 BCM_IF_ERROR_RETURN 352 (_bcm_tr2_cosq_gport_delete(unit, port)); 353 } 354 } 355 } 356 357 /* Destroy profile table cache */ 358 BCM_IF_ERROR_RETURN 359 (soc_profile_mem_destroy(unit, _tr2_cos_map_profile[unit])); 360 sal_free(_tr2_cos_map_profile[unit]); 361 _tr2_cos_map_profile[unit] = NULL; 362 363 sal_free(_tr2_num_port_cosq[unit]); 364 _tr2_num_port_cosq[unit] = NULL; 365 } 366 367 for (cosq = 0; cosq < 8; cosq++) { 368 weights[cosq] = 0; 369 } 370 371 if (!software_state_only) 372 { 373 PBMP_ALL_ITER(unit, port) { 374 if (IS_CPU_PORT(unit, port)) { 375 continue; 376 } 377 378 /* Clear bandwidth settings on port */ 379 for (cosq = 0; cosq < 8; cosq++) { 380 BCM_IF_ERROR_RETURN 381 (bcm_tr2_cosq_port_bandwidth_set(unit, port, cosq, 382 0, 0, 0, 0)); 383 } 384 385 /* Clear scheduling settings on port */ 386 BCM_IF_ERROR_RETURN 387 (_bcm_tr2_cosq_port_sched_set(unit, 388 ESCONFIGr, COSWEIGHTSr, MINSPCONFIGr, 389 port, 0, 8, weights, 390 BCM_COSQ_WEIGHTED_ROUND_ROBIN)); 391 /* Clear discard settings on port */ 392 393 for (cosq = 0; cosq < 8; cosq++) { 394 BCM_IF_ERROR_RETURN 395 (_bcm_tr2_cosq_discard_set(unit, port, 396 BCM_COSQ_DISCARD_COLOR_ALL | 397 BCM_COSQ_DISCARD_NONTCP, cosq, 398 WREDCONFIG_PACKETr, 399 WREDPARAM_PACKETr, 400 WREDPARAM_YELLOW_PACKETr, 401 WREDPARAM_RED_PACKETr, 402 WREDPARAM_NONTCP_PACKETr, 403 TR2_PACKET_FIELD_MAX, 404 TR2_PACKET_FIELD_MAX, 100, 0)); 405 } 406 } 407 408 /* Disable WRED on all cosq level */ 409 BCM_IF_ERROR_RETURN (bcm_tr2_cosq_discard_set(unit, 0)); 410 } 411 412 413 return BCM_E_NONE; 414 } 415 416 /* 417 * Function: 418 * bcm_cosq_config_set 419 * Purpose: 420 * Set the number of COS queues 421 * Parameters: 422 * unit - Unit number. 423 * numq - number of COS queues (1-8). 424 * Returns: 425 * BCM_E_XXX 426 */ 427 428 int 429 bcm_tr2_cosq_config_set(int unit, int numq) 430 { 431 int cos, prio, ratio, remain; 432 uint32 index, egr_index, minsp; 433 soc_mem_t mem = PORT_COS_MAPm; 434 soc_mem_t egr_mem = EGR_COS_MAPm; 435 int entry_words; 436 bcm_pbmp_t ports; 437 bcm_port_t port; 438 port_cos_map_entry_t cos_map_array[TR2_COS_MAP_ENTRIES_PER_SET]; 439 egr_cos_map_entry_t egr_cos_map_array[TR2_COS_MAP_ENTRIES_PER_SET]; 440 void *entries[1], *egr_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 sal_memset(cos_map_array, 0, 453 COUNTOF(cos_map_array) * sizeof(port_cos_map_entry_t)); 454 entries[0] = &cos_map_array; 455 if (_tr2_cos_map_profile[unit] == NULL) { 456 _tr2_cos_map_profile[unit] = sal_alloc(sizeof(soc_profile_mem_t), 457 "COS_MAP Profile Mem"); 458 if (_tr2_cos_map_profile[unit] == NULL) { 459 return BCM_E_MEMORY; 460 } 461 soc_profile_mem_t_init(_tr2_cos_map_profile[unit]); 462 } 463 /* Create profile table cache (or re-init if it already exists) */ 464 entry_words = sizeof(port_cos_map_entry_t)/ sizeof(uint32); 465 SOC_IF_ERROR_RETURN(soc_profile_mem_create(unit, &mem, &entry_words, 1, 466 _tr2_cos_map_profile[unit])); 467 468 sal_memset(egr_cos_map_array, 0, 469 COUNTOF(egr_cos_map_array) * sizeof(egr_cos_map_entry_t)); 470 egr_entries[0] = &egr_cos_map_array; 471 if (_tr2_cos_egr_map_profile[unit] == NULL) { 472 _tr2_cos_egr_map_profile[unit] = sal_alloc(sizeof(soc_profile_mem_t), 473 "EGR COS_MAP Profile Mem"); 474 if (_tr2_cos_egr_map_profile[unit] == NULL) { 475 return BCM_E_MEMORY; 476 } 477 soc_profile_mem_t_init(_tr2_cos_egr_map_profile[unit]); 478 } 479 /* Create profile table cache (or re-init if it already exists) */ 480 entry_words = sizeof(egr_cos_map_entry_t)/ sizeof(uint32); 481 SOC_IF_ERROR_RETURN(soc_profile_mem_create(unit, &egr_mem, &entry_words, 1, 482 _tr2_cos_egr_map_profile[unit])); 483 484 if (SOC_WARM_BOOT(unit)) { /* Warm Boot */ 485 int i; 486 uint32 val; 487 uint64 val64; 488 489 /* Gather reference count for cosq map profile tables */ 490 BCM_PBMP_ASSIGN(ports, PBMP_ALL(unit)); 491 PBMP_ITER(ports, port) { 492 SOC_IF_ERROR_RETURN(READ_COS_MAP_SELr(unit, port, &val)); 493 index = soc_reg_field_get(unit, COS_MAP_SELr, val, SELECTf); 494 index *= TR2_COS_MAP_ENTRIES_PER_SET; 495 for (i = 0; i < TR2_COS_MAP_ENTRIES_PER_SET; i++) { 496 SOC_PROFILE_MEM_REFERENCE 497 (unit, _tr2_cos_map_profile[unit], 498 index + i, 1); 499 SOC_PROFILE_MEM_ENTRIES_PER_SET 500 (unit, _tr2_cos_map_profile[unit], 501 index + i, TR2_COS_MAP_ENTRIES_PER_SET); 502 } 503 504 if (soc_mem_field_valid(unit, EGR_COS_MAPm, REDIRECT_COSf)) { 505 SOC_IF_ERROR_RETURN 506 (READ_EGR_PORT_64r(unit, port, &val64)); 507 index = soc_reg64_field32_get(unit, EGR_PORT_64r, val64, 508 EGR_COS_MAP_SELf); 509 index *= TR2_COS_MAP_ENTRIES_PER_SET; 510 for (i = 0; i < TR2_COS_MAP_ENTRIES_PER_SET; i++) { 511 SOC_PROFILE_MEM_REFERENCE 512 (unit, _tr2_cos_egr_map_profile[unit], 513 index + i, 1); 514 SOC_PROFILE_MEM_ENTRIES_PER_SET 515 (unit, _tr2_cos_egr_map_profile[unit], 516 index + i, TR2_COS_MAP_ENTRIES_PER_SET); 517 } 518 } 519 520 #ifndef BCM_COSQ_HIGIG_MAP_DISABLE 521 if (IS_HG_PORT(unit, port) || port == CMIC_PORT(unit)) { 522 SOC_IF_ERROR_RETURN(READ_ICOS_MAP_SELr(unit, port, &val)); 523 index = soc_reg_field_get(unit, ICOS_MAP_SELr, val, SELECTf); 524 index *= TR2_COS_MAP_ENTRIES_PER_SET; 525 for (i = 0; i < TR2_COS_MAP_ENTRIES_PER_SET; i++) { 526 SOC_PROFILE_MEM_REFERENCE 527 (unit, _tr2_cos_map_profile[unit], 528 index + i, 1); 529 SOC_PROFILE_MEM_ENTRIES_PER_SET 530 (unit, _tr2_cos_map_profile[unit], 531 index + i, TR2_COS_MAP_ENTRIES_PER_SET); 532 } 533 534 if (soc_mem_field_valid(unit, EGR_COS_MAPm, REDIRECT_COSf)) { 535 SOC_IF_ERROR_RETURN 536 (READ_IEGR_PORT_64r(unit, port, &val64)); 537 index = soc_reg64_field32_get(unit, IEGR_PORT_64r, val64, 538 EGR_COS_MAP_SELf); 539 index *= TR2_COS_MAP_ENTRIES_PER_SET; 540 for (i = 0; i < TR2_COS_MAP_ENTRIES_PER_SET; i++) { 541 SOC_PROFILE_MEM_REFERENCE 542 (unit, _tr2_cos_egr_map_profile[unit], 543 index + i, 1); 544 SOC_PROFILE_MEM_ENTRIES_PER_SET 545 (unit, _tr2_cos_egr_map_profile[unit], 546 index + i, TR2_COS_MAP_ENTRIES_PER_SET); 547 } 548 } 549 } 550 #endif /* BCM_COSQ_HIGIG_MAP_DISABLE */ 551 } 552 553 _tr2_num_cosq[unit] = numq; 554 555 return BCM_E_NONE; 556 } 557 558 ratio = 8 / numq; 559 remain = 8 % numq; 560 cos = 0; 561 for (prio = 0; prio < 8; prio++) { 562 soc_mem_field32_set(unit, PORT_COS_MAPm, 563 &cos_map_array[prio], COSf, cos); 564 if (soc_mem_field_valid(unit,PORT_COS_MAPm,HG_COSf)) { 565 soc_mem_field32_set(unit, PORT_COS_MAPm, 566 &cos_map_array[prio], HG_COSf, 0); 567 } 568 if ((prio + 1) == (((cos + 1) * ratio) + 569 ((remain < (numq - cos)) ? 0 : 570 (remain - (numq - cos) + 1)))) { 571 cos++; 572 } 573 } 574 575 /* Map remaining internal priority levels to highest priority cosq */ 576 cos = numq - 1; 577 for (prio = 8; prio < 16; prio++) { 578 soc_mem_field32_set(unit, PORT_COS_MAPm, 579 &cos_map_array[prio], COSf, cos); 580 if (soc_mem_field_valid(unit,PORT_COS_MAPm,HG_COSf)) { 581 soc_mem_field32_set(unit, PORT_COS_MAPm, 582 &cos_map_array[prio], HG_COSf, 0); 583 } 584 } 585 586 /* Map internal priority levels to CPU CoS queues */ 587 BCM_IF_ERROR_RETURN(_bcm_esw_cpu_cosq_mapping_default_set(unit, numq)); 588 589 /* Map egress priority */ 590 if (soc_mem_field_valid(unit, EGR_COS_MAPm, REDIRECT_COSf)) { 591 ratio = 16 / numq; 592 remain = 16 % numq; 593 cos = 0; 594 for (prio = 0; prio < 16; prio++) { 595 soc_mem_field32_set(unit, EGR_COS_MAPm, 596 &egr_cos_map_array[prio], REDIRECT_COSf, cos); 597 if ((prio + 1) == (((cos + 1) * ratio) + 598 ((remain < (numq - cos)) ? 0 : 599 (remain - (numq - cos) + 1)))) { 600 cos++; 601 } 602 } 603 /* Map egress priority */ 604 if (soc_mem_field_valid(unit, EGR_CPU_COS_MAPm, REDIRECT_COSf)) { 605 BCM_IF_ERROR_RETURN( 606 _bcm_tr2_egr_cpu_cos_map(unit, numq)); 607 } 608 } 609 610 /* Add a profile mem entry for each port */ 611 BCM_PBMP_ASSIGN(ports, PBMP_ALL(unit)); 612 PBMP_ITER(ports, port) { 613 SOC_IF_ERROR_RETURN 614 (soc_profile_mem_add(unit, _tr2_cos_map_profile[unit], 615 (void *) &entries, 616 TR2_COS_MAP_ENTRIES_PER_SET, &index)); 617 SOC_IF_ERROR_RETURN 618 (soc_reg_field32_modify(unit, COS_MAP_SELr, port, SELECTf, 619 index / TR2_COS_MAP_ENTRIES_PER_SET)); 620 if (soc_mem_field_valid(unit, EGR_COS_MAPm, REDIRECT_COSf)) { 621 SOC_IF_ERROR_RETURN( 622 soc_profile_mem_add(unit, _tr2_cos_egr_map_profile[unit], 623 (void *) &egr_entries, 624 TR2_COS_MAP_ENTRIES_PER_SET, &egr_index)); 625 SOC_IF_ERROR_RETURN 626 (soc_reg_field32_modify(unit, EGR_PORT_64r, port, 627 EGR_COS_MAP_SELf, 628 egr_index / TR2_COS_MAP_ENTRIES_PER_SET)); 629 } 630 #ifndef BCM_COSQ_HIGIG_MAP_DISABLE 631 if ((IS_HG_PORT(unit, port) || port == CMIC_PORT(unit))) { 632 SOC_IF_ERROR_RETURN 633 (soc_profile_mem_add(unit, _tr2_cos_map_profile[unit], 634 (void *) &entries, 635 TR2_COS_MAP_ENTRIES_PER_SET, &index)); 636 if (soc_mem_field_valid(unit, EGR_COS_MAPm, REDIRECT_COSf)) { 637 SOC_IF_ERROR_RETURN( 638 soc_profile_mem_add(unit, _tr2_cos_egr_map_profile[unit], 639 (void *) &egr_entries, 640 TR2_COS_MAP_ENTRIES_PER_SET, 641 &egr_index)); 642 SOC_IF_ERROR_RETURN 643 (soc_reg_field32_modify(unit, IEGR_PORT_64r, port, 644 EGR_COS_MAP_SELf, 645 egr_index / TR2_COS_MAP_ENTRIES_PER_SET)); 646 } 647 648 SOC_IF_ERROR_RETURN 649 (soc_reg_field32_modify(unit, ICOS_MAP_SELr, port, SELECTf, 650 index / TR2_COS_MAP_ENTRIES_PER_SET)); 651 } 652 #endif 653 } 654 655 #ifdef BCM_COSQ_HIGIG_MAP_DISABLE 656 /* identity mapping for higig ports */ 657 658 /* map prio0->cos0, prio1->cos1, ... , prio7->cos7 */ 659 for (prio = 0; prio < 8; prio++) { 660 soc_mem_field32_set(unit, PORT_COS_MAPm, 661 &cos_map_array[prio], COSf, prio); 662 if (soc_mem_field_valid(unit,PORT_COS_MAPm,HG_COSf)) { 663 soc_mem_field32_set(unit, PORT_COS_MAPm, 664 &cos_map_array[prio], HG_COSf, 0); 665 } 666 } 667 /* Map remaining internal priority levels to highest priority cosq */ 668 for (prio = 8; prio < 16; prio++) { 669 soc_mem_field32_set(unit, PORT_COS_MAPm, 670 &cos_map_array[prio], COSf, 7); 671 if (soc_mem_field_valid(unit,PORT_COS_MAPm,HG_COSf)) { 672 soc_mem_field32_set(unit, PORT_COS_MAPm, 673 &cos_map_array[prio], HG_COSf, 0); 674 } 675 } 676 PBMP_ITER(ports, port) { 677 if (IS_HG_PORT(unit, port) || port == CMIC_PORT(unit)) { 678 SOC_IF_ERROR_RETURN 679 (soc_profile_mem_add(unit, _tr2_cos_map_profile[unit], 680 (void *) &entries, 681 TR2_COS_MAP_ENTRIES_PER_SET, &index)); 682 soc_reg_field32_modify(unit, ICOS_MAP_SELr, port, 683 SELECTf, 684 (index / TR2_COS_MAP_ENTRIES_PER_SET)); 685 } 686 } 687 #endif 688 689 /* Always strict priority for SC and QM COS queues */ 690 PBMP_ITER(ports, port) { 691 SOC_IF_ERROR_RETURN 692 (READ_MINSPCONFIGr(unit, port, &minsp)); 693 soc_reg_field_set(unit, MINSPCONFIGr, &minsp, COS8_IS_SPf, 1); 694 soc_reg_field_set(unit, MINSPCONFIGr, &minsp, COS9_IS_SPf, 1); 695 SOC_IF_ERROR_RETURN 696 (WRITE_MINSPCONFIGr(unit, port, minsp)); 697 } 698 699 _tr2_num_cosq[unit] = numq; 700 701 #ifdef BCM_WARM_BOOT_SUPPORT 702 SOC_CONTROL_LOCK(unit); 703 SOC_CONTROL(unit)->scache_dirty = 1; 704 SOC_CONTROL_UNLOCK(unit); 705 #endif 706 707 return BCM_E_NONE; 708 } 709 710 /* 711 * Function: 712 * bcm_cosq_config_get 713 * Purpose: 714 * Get the number of cos queues 715 * Parameters: 716 * unit - StrataSwitch unit number. 717 * numq - (Output) number of cosq 718 * Returns: 719 * BCM_E_XXX 720 */ 721 722 int 723 bcm_tr2_cosq_config_get(int unit, int *numq) 724 { 725 if (_tr2_num_cosq[unit] == 0) { 726 return BCM_E_INIT; 727 } 728 729 if (numq != NULL) { 730 *numq = _tr2_num_cosq[unit]; 731 } 732 733 return BCM_E_NONE; 734 } 735 736 /* 737 * Function: 738 * bcm_cosq_mapping_set 739 * Purpose: 740 * Set which cosq a given priority should fall into 741 * Parameters: 742 * unit - StrataSwitch unit number. 743 * priority - Priority value to map 744 * cosq - COS queue to map to 745 * Returns: 746 * BCM_E_XXX 747 */ 748 749 int 750 bcm_tr2_cosq_mapping_set(int unit, bcm_port_t port, 751 bcm_cos_t priority, bcm_cos_queue_t cosq) 752 { 753 uint32 val, old_index, new_index; 754 int i; 755 port_cos_map_entry_t cos_map_array[TR2_COS_MAP_ENTRIES_PER_SET], *entry_p; 756 void *entries[1]; 757 bcm_pbmp_t ports; 758 759 if (priority < 0 || priority >= 16) { 760 return (BCM_E_PARAM); 761 } 762 763 if (cosq < 0 || cosq >= 8) { 764 return (BCM_E_PARAM); 765 } 766 767 if (port == -1) { /* all ports */ 768 BCM_PBMP_ASSIGN(ports, PBMP_ALL(unit)); 769 } else if (SOC_PORT_VALID(unit, port) && IS_ALL_PORT(unit, port)) { 770 BCM_PBMP_CLEAR(ports); 771 BCM_PBMP_PORT_ADD(ports, port); 772 } else { 773 return BCM_E_PORT; 774 } 775 776 entries[0] = &cos_map_array; 777 778 PBMP_ITER(ports, port) { 779 SOC_IF_ERROR_RETURN(READ_COS_MAP_SELr(unit, port, &val)); 780 old_index = soc_reg_field_get(unit, COS_MAP_SELr, val, SELECTf); 781 old_index *= TR2_COS_MAP_ENTRIES_PER_SET; 782 783 /* get current mapping profile values */ 784 for (i = 0; i < TR2_COS_MAP_ENTRIES_PER_SET; i++) { 785 entry_p = SOC_PROFILE_MEM_ENTRY(unit, _tr2_cos_map_profile[unit], 786 port_cos_map_entry_t *, (old_index + i)); 787 memcpy(&cos_map_array[i], entry_p, sizeof(*entry_p)); 788 } 789 soc_mem_field32_set(unit, PORT_COS_MAPm, 790 &cos_map_array[priority], COSf, cosq); 791 SOC_IF_ERROR_RETURN 792 (soc_profile_mem_add(unit, _tr2_cos_map_profile[unit], 793 (void *) &entries, 794 TR2_COS_MAP_ENTRIES_PER_SET, &new_index)); 795 SOC_IF_ERROR_RETURN 796 (soc_reg_field32_modify(unit, COS_MAP_SELr, port, 797 SELECTf, 798 new_index / TR2_COS_MAP_ENTRIES_PER_SET)); 799 SOC_IF_ERROR_RETURN 800 (soc_profile_mem_delete(unit, _tr2_cos_map_profile[unit], old_index)); 801 802 #ifndef BCM_COSQ_HIGIG_MAP_DISABLE 803 if (IS_HG_PORT(unit, port) || port == CMIC_PORT(unit)) { 804 SOC_IF_ERROR_RETURN 805 (soc_profile_mem_add(unit, _tr2_cos_map_profile[unit], 806 (void *) &entries, 807 TR2_COS_MAP_ENTRIES_PER_SET, &new_index)); 808 SOC_IF_ERROR_RETURN 809 (soc_reg_field32_modify(unit, ICOS_MAP_SELr, port, 810 SELECTf, 811 new_index / TR2_COS_MAP_ENTRIES_PER_SET)); 812 SOC_IF_ERROR_RETURN 813 (soc_profile_mem_delete(unit, _tr2_cos_map_profile[unit], old_index)); 814 } 815 #endif 816 } 817 return BCM_E_NONE; 818 } 819 820 /* 821 * Function: 822 * bcm_cosq_mapping_get 823 * Purpose: 824 * Determine which COS queue a given priority currently maps to. 825 * Parameters: 826 * unit - StrataSwitch unit number. 827 * priority - Priority value 828 * cosq - (Output) COS queue number 829 * Returns: 830 * BCM_E_XXX 831 */ 832 833 int 834 bcm_tr2_cosq_mapping_get(int unit, bcm_port_t port, 835 bcm_cos_t priority, bcm_cos_queue_t *cosq) 836 { 837 uint32 val; 838 int index; 839 port_cos_map_entry_t *entry_p; 840 841 if (priority < 0 || priority >= 16) { 842 return (BCM_E_PARAM); 843 } 844 845 if (port == -1) { 846 port = REG_PORT_ANY; 847 } else if (!SOC_PORT_VALID(unit, port) || !IS_ALL_PORT(unit, port)) { 848 return BCM_E_PORT; 849 } 850 851 SOC_IF_ERROR_RETURN(READ_COS_MAP_SELr(unit, port, &val)); 852 index = soc_reg_field_get(unit, COS_MAP_SELr, val, SELECTf); 853 index *= TR2_COS_MAP_ENTRIES_PER_SET; 854 855 entry_p = SOC_PROFILE_MEM_ENTRY(unit, _tr2_cos_map_profile[unit], 856 port_cos_map_entry_t *, 857 (index + priority)); 858 *cosq = soc_mem_field32_get(unit, PORT_COS_MAPm, entry_p, COSf); 859 return BCM_E_NONE; 860 } 861 862 STATIC int 863 _bcm_tr2_cosq_bucket_set(int unit, bcm_port_t port, 864 bcm_cos_queue_t cosq, 865 uint32 min_quantum, /* kbps or packet/second */ 866 uint32 max_quantum, /* kbps or packet/second */ 867 uint32 kbits_burst_min, 868 uint32 kbits_burst_max, 869 uint32 flags) 870 { 871 uint32 regval; 872 uint32 bucket_val = 0; 873 uint64 regval_64, tmp; 874 uint32 refresh_rate, bucketsize, granularity = 3, meter_flags = flags; 875 int refresh_bitsize, bucket_bitsize; 876 877 /* 878 * To set the new Bandwidth settings, the procedure adopted is 879 * a. reset MAXBUCKETCONFIG, MINBUCKETCONFIG, MAXBUCKET,MINBUCKET 880 * b. update MAXBUCKETCONFIG and MINBUCKETCONFIG with new values passed 881 * c. if MISCCONFIG.METERING_CLK_EN not set before, enable it. 882 */ 883 884 BCM_IF_ERROR_RETURN(READ_MISCCONFIGr(unit, ®val)); 885 if (soc_reg_field_get(unit, MISCCONFIGr, regval, ITU_MODE_SELf)) { 886 meter_flags |= _BCM_XGS_METER_FLAG_NON_LINEAR; 887 } 888 meter_flags |= _BCM_XGS_METER_FLAG_GRANULARITY; 889 890 /* Disable egress metering for this port */ 891 BCM_IF_ERROR_RETURN(READ_MAXBUCKETCONFIG_64r(unit, port, cosq, ®val_64)); 892 soc_reg64_field32_set(unit, MAXBUCKETCONFIG_64r, ®val_64, MAX_REFRESHf, 0); 893 soc_reg64_field32_set(unit, MAXBUCKETCONFIG_64r, ®val_64, MAX_THDf, 0); 894 BCM_IF_ERROR_RETURN(WRITE_MAXBUCKETCONFIG_64r(unit, port, cosq, regval_64)); 895 896 BCM_IF_ERROR_RETURN(READ_MINBUCKETCONFIG_64r(unit, port, cosq, ®val_64)); 897 soc_reg64_field32_set(unit, MINBUCKETCONFIG_64r, ®val_64, MIN_REFRESHf, 0); 898 soc_reg64_field32_set(unit, MINBUCKETCONFIG_64r, ®val_64, MIN_THDf, 0); 899 BCM_IF_ERROR_RETURN(WRITE_MINBUCKETCONFIG_64r(unit, port, cosq, regval_64)); 900 901 /*reset the MAXBUCKET register*/ 902 soc_reg_field_set(unit, MAXBUCKETr, &bucket_val, MAX_BUCKETf, 0); 903 soc_reg_field_set(unit, MAXBUCKETr, &bucket_val, OUT_PROFILE_FLAGf, 0); 904 BCM_IF_ERROR_RETURN(WRITE_MAXBUCKETr(unit, port, cosq, bucket_val)); 905 906 /*reset the MINBUCKET register value*/ 907 soc_reg_field_set(unit, MINBUCKETr, &bucket_val, MIN_BUCKETf, 0); 908 soc_reg_field_set(unit, MINBUCKETr, &bucket_val, OUT_PROFILE_FLAGf, 0); 909 BCM_IF_ERROR_RETURN(WRITE_MINBUCKETr(unit, port, cosq, bucket_val)); 910 911 refresh_bitsize = 912 soc_reg_field_length(unit, MINBUCKETCONFIG_64r, MIN_REFRESHf); 913 bucket_bitsize = 914 soc_reg_field_length(unit, MINBUCKETCONFIG_64r, MIN_THDf); 915 916 BCM_IF_ERROR_RETURN 917 (_bcm_xgs_kbits_to_bucket_encoding(min_quantum, kbits_burst_min, 918 meter_flags, refresh_bitsize, bucket_bitsize, 919 &refresh_rate, &bucketsize, &granularity)); 920 921 COMPILER_64_ZERO(regval_64); 922 soc_reg64_field32_set(unit, MINBUCKETCONFIG_64r, ®val_64, 923 METER_GRANf, granularity); 924 soc_reg64_field32_set(unit, MINBUCKETCONFIG_64r, ®val_64, 925 MIN_REFRESHf, refresh_rate); 926 soc_reg64_field32_set(unit, MINBUCKETCONFIG_64r, 927 ®val_64, MIN_THDf, bucketsize); 928 BCM_IF_ERROR_RETURN 929 (WRITE_MINBUCKETCONFIG_64r(unit, port, cosq, regval_64)); 930 931 refresh_bitsize = 932 soc_reg_field_length(unit, MAXBUCKETCONFIG_64r, MAX_REFRESHf); 933 bucket_bitsize = 934 soc_reg_field_length(unit, MAXBUCKETCONFIG_64r, MAX_THDf); 935 936 BCM_IF_ERROR_RETURN 937 (_bcm_xgs_kbits_to_bucket_encoding(max_quantum, kbits_burst_max, 938 meter_flags, refresh_bitsize, bucket_bitsize, 939 &refresh_rate, &bucketsize, &granularity)); 940 941 COMPILER_64_ZERO(regval_64); 942 soc_reg64_field32_set(unit, MAXBUCKETCONFIG_64r, ®val_64, 943 METER_GRANf, granularity); 944 soc_reg64_field32_set(unit, MAXBUCKETCONFIG_64r, ®val_64, 945 MAX_REFRESHf, refresh_rate); 946 soc_reg64_field32_set(unit, MAXBUCKETCONFIG_64r, ®val_64, MAX_THDf, 947 bucketsize); 948 BCM_IF_ERROR_RETURN(WRITE_MAXBUCKETCONFIG_64r(unit, port, cosq, regval_64)); 949 950 if (flags & _BCM_XGS_METER_FLAG_PACKET_MODE) { 951 BCM_IF_ERROR_RETURN(READ_SHAPING_MODEr(unit, port, ®val_64)); 952 COMPILER_64_SET(tmp, 0, 1); 953 COMPILER_64_SHL(tmp, cosq); 954 COMPILER_64_OR(regval_64, tmp); 955 BCM_IF_ERROR_RETURN(WRITE_SHAPING_MODEr(unit, port, regval_64)); 956 } else { 957 BCM_IF_ERROR_RETURN(READ_SHAPING_MODEr(unit, port, ®val_64)); 958 COMPILER_64_SET(tmp, 0, 1); 959 COMPILER_64_SHL(tmp, cosq); 960 COMPILER_64_NOT(tmp); 961 COMPILER_64_AND(regval_64, tmp); 962 BCM_IF_ERROR_RETURN(WRITE_SHAPING_MODEr(unit, port, regval_64)); 963 } 964 965 /* MISCCONFIG.METERING_CLK_EN is set by chip init */ 966 967 return BCM_E_NONE; 968 } 969 970 STATIC int 971 _bcm_tr2_cosq_bucket_get(int unit, bcm_port_t port, 972 bcm_cos_queue_t cosq, 973 uint32 *min_quantum, /* kbps or packet/second */ 974 uint32 *max_quantum, /* kbps or packet/second */ 975 uint32 *kbits_burst_min, uint32 *kbits_burst_max, 976 uint32 *flags) 977 { 978 uint32 regval; 979 uint64 regval_64; 980 uint32 refresh_rate = 0, bucketsize = 0, granularity = 3, meter_flags; 981 982 if (!min_quantum || !max_quantum || !flags) { 983 return (BCM_E_PARAM); 984 } 985 986 meter_flags = *flags; 987 988 BCM_IF_ERROR_RETURN(READ_MISCCONFIGr(unit, ®val)); 989 if (soc_reg_field_get(unit, MISCCONFIGr, regval, ITU_MODE_SELf)) { 990 meter_flags |= _BCM_XGS_METER_FLAG_NON_LINEAR; 991 } 992 meter_flags |= _BCM_XGS_METER_FLAG_GRANULARITY; 993 994 BCM_IF_ERROR_RETURN(READ_MAXBUCKETCONFIG_64r(unit, port, cosq, ®val_64)); 995 granularity = soc_reg64_field32_get(unit, MAXBUCKETCONFIG_64r, 996 regval_64, METER_GRANf); 997 refresh_rate = soc_reg64_field32_get(unit, MAXBUCKETCONFIG_64r, 998 regval_64, MAX_REFRESHf); 999 bucketsize = soc_reg64_field32_get(unit, MAXBUCKETCONFIG_64r, 1000 regval_64, MAX_THDf); 1001 1002 BCM_IF_ERROR_RETURN 1003 (_bcm_xgs_bucket_encoding_to_kbits(refresh_rate, bucketsize, 1004 granularity, meter_flags, 1005 max_quantum, kbits_burst_max)); 1006 1007 BCM_IF_ERROR_RETURN(READ_MINBUCKETCONFIG_64r(unit, port, cosq, ®val_64)); 1008 1009 granularity = soc_reg64_field32_get(unit, MINBUCKETCONFIG_64r, 1010 regval_64, METER_GRANf); 1011 refresh_rate = soc_reg64_field32_get(unit, MINBUCKETCONFIG_64r, 1012 regval_64, MIN_REFRESHf); 1013 bucketsize = soc_reg64_field32_get(unit, MINBUCKETCONFIG_64r, 1014 regval_64, MIN_THDf); 1015 BCM_IF_ERROR_RETURN 1016 (_bcm_xgs_bucket_encoding_to_kbits(refresh_rate, bucketsize, 1017 granularity, meter_flags, 1018 min_quantum, kbits_burst_min)); 1019 1020 return BCM_E_NONE; 1021 } 1022 1023 int 1024 bcm_tr2_cosq_port_bandwidth_set(int unit, bcm_port_t port, 1025 bcm_cos_queue_t cosq, 1026 uint32 min_quantum, /* kbps or packet/second */ 1027 uint32 max_quantum, /* kbps or packet/second */ 1028 uint32 burst_quantum, /* kbps or packet/second */ 1029 uint32 flags) 1030 { 1031 1032 if (cosq < 0) { 1033 return BCM_E_PARAM; 1034 } 1035 1036 /*keep place with original*/ 1037 return _bcm_tr2_cosq_bucket_set(unit, port, cosq, min_quantum, max_quantum, 1038 min_quantum, burst_quantum, flags); 1039 } 1040 1041 int 1042 bcm_tr2_cosq_port_bandwidth_get(int unit, bcm_port_t port, 1043 bcm_cos_queue_t cosq, 1044 uint32 *min_quantum, /* kbps or packet/second */ 1045 uint32 *max_quantum, /* kbps or packet/second */ 1046 uint32 *burst_quantum, /* kbps or packet/second */ 1047 uint32 *flags) 1048 { 1049 uint32 kbit_burst_min; 1050 1051 if (cosq < -1) { 1052 return BCM_E_PARAM; 1053 } 1054 1055 BCM_IF_ERROR_RETURN(_bcm_tr2_cosq_bucket_get(unit, port, cosq, 1056 min_quantum, max_quantum, &kbit_burst_min, 1057 burst_quantum, flags)); 1058 return BCM_E_NONE; 1059 } 1060 1061 int 1062 bcm_tr2_cosq_port_pps_set(int unit, bcm_port_t port, 1063 bcm_cos_queue_t cosq, int pps) 1064 { 1065 uint32 min, max, burst, flags = _BCM_XGS_METER_FLAG_PACKET_MODE; 1066 if (!IS_CPU_PORT(unit, port)) { 1067 return BCM_E_PORT; 1068 } else if (cosq >= NUM_CPU_COSQ(unit)) { 1069 return BCM_E_PARAM; 1070 } 1071 1072 /* Get the current PPS and BURST settings */ 1073 BCM_IF_ERROR_RETURN 1074 (bcm_tr2_cosq_port_bandwidth_get(unit, port, cosq, 1075 &min, &max, &burst, &flags)); 1076 /* Set the current PPS setting */ 1077 return bcm_tr2_cosq_port_bandwidth_set(unit, port, cosq, 1078 min, pps, burst, flags); 1079 } 1080 1081 int 1082 bcm_tr2_cosq_port_pps_get(int unit, bcm_port_t port, 1083 bcm_cos_queue_t cosq, int *pps) 1084 { 1085 uint32 min, max, burst, flags = _BCM_XGS_METER_FLAG_PACKET_MODE; 1086 1087 if (!IS_CPU_PORT(unit, port)) { 1088 return BCM_E_PORT; 1089 } else if (cosq >= NUM_CPU_COSQ(unit)) { 1090 return BCM_E_PARAM; 1091 } 1092 1093 BCM_IF_ERROR_RETURN(bcm_tr2_cosq_port_bandwidth_get(unit, port, cosq, 1094 &min, &max, &burst, &flags)); 1095 *pps = max; 1096 return BCM_E_NONE; 1097 } 1098 1099 int 1100 bcm_tr2_cosq_port_burst_set(int unit, bcm_port_t port, 1101 bcm_cos_queue_t cosq, int burst) 1102 { 1103 uint32 min, max, cur_burst, flags = _BCM_XGS_METER_FLAG_PACKET_MODE; 1104 1105 if (!IS_CPU_PORT(unit, port)) { 1106 return BCM_E_PORT; 1107 } else if (cosq >= NUM_CPU_COSQ(unit)) { 1108 return BCM_E_PARAM; 1109 } 1110 1111 /* Get the current PPS and BURST settings */ 1112 BCM_IF_ERROR_RETURN(bcm_tr2_cosq_port_bandwidth_get(unit, port, cosq, 1113 &min, &max, &cur_burst, &flags)); 1114 /* Replace the current BURST setting, keep PPS the same */ 1115 return bcm_tr2_cosq_port_bandwidth_set(unit, port, cosq, min, max, 1116 burst, flags); 1117 } 1118 1119 int 1120 bcm_tr2_cosq_port_burst_get(int unit, bcm_port_t port, 1121 bcm_cos_queue_t cosq, int *burst) 1122 { 1123 uint32 min, max, cur_burst, flags = _BCM_XGS_METER_FLAG_PACKET_MODE; 1124 1125 if (!IS_CPU_PORT(unit, port)) { 1126 return BCM_E_PORT; 1127 } else if (cosq >= NUM_CPU_COSQ(unit)) { 1128 return BCM_E_PARAM; 1129 } 1130 1131 BCM_IF_ERROR_RETURN(bcm_tr2_cosq_port_bandwidth_get(unit, port, cosq, 1132 &min, &max, &cur_burst, &flags)); 1133 *burst = cur_burst; 1134 return BCM_E_NONE; 1135 } 1136 1137 int 1138 _bcm_tr2_cosq_port_resolve(int unit, bcm_gport_t gport, 1139 bcm_module_t *modid, bcm_port_t *port, 1140 bcm_trunk_t *trunk_id, int *id) 1141 { 1142 bcm_module_t mod_in; 1143 bcm_port_t port_in; 1144 1145 if (BCM_GPORT_IS_SCHEDULER(gport)) { 1146 mod_in = (BCM_GPORT_SCHEDULER_GET(gport) >> 8) & 0xff; 1147 port_in = BCM_GPORT_SCHEDULER_GET(gport) & 0xff; 1148 *id = BCM_GPORT_SCHEDULER_GET(gport); 1149 *trunk_id = -1; 1150 1151 /* Since the modid/port in the scheduler GPORT is the 1152 * applications modid/port space, convert to local space. 1153 */ 1154 BCM_IF_ERROR_RETURN 1155 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET, 1156 mod_in, port_in, modid, port)); 1157 1158 if (!_tr2_num_port_cosq[unit]) { 1159 return BCM_E_INIT; 1160 } else if (!SOC_PBMP_MEMBER(_tr2_cosq_24q_ports[unit], *port)) { 1161 return BCM_E_BADID; 1162 } else if (_tr2_num_port_cosq[unit][*port] == 0) { 1163 return BCM_E_NOT_FOUND; 1164 } 1165 } else { 1166 return BCM_E_BADID; 1167 } 1168 return BCM_E_NONE; 1169 } 1170 1171 STATIC int 1172 _bcm_tr2_cosq_resolve_mod_port(int unit, bcm_gport_t gport, 1173 bcm_module_t *modid, bcm_port_t *port, 1174 bcm_trunk_t *trunk_id) 1175 { 1176 int gport_id, result; 1177 1178 BCM_IF_ERROR_RETURN 1179 (_bcm_esw_gport_resolve(unit, gport, modid, 1180 port, trunk_id, &gport_id)); 1181 BCM_IF_ERROR_RETURN( 1182 _bcm_esw_modid_is_local(unit, *modid, &result)); 1183 1184 if (TRUE != result) { 1185 return BCM_E_PORT; 1186 } 1187 return BCM_E_NONE; 1188 } 1189 1190 STATIC int 1191 _bcm_tr2_cosq_discard_cap_enable_set(int unit, bcm_port_t port, 1192 bcm_cos_queue_t cosq, soc_reg_t config_reg, 1193 uint32 flags) 1194 { 1195 uint32 val, addr; 1196 1197 addr = soc_reg_addr(unit, config_reg, port, cosq); 1198 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &val)); 1199 1200 if (flags & BCM_COSQ_DISCARD_CAP_AVERAGE) { 1201 soc_reg_field_set(unit, config_reg, &val, CAP_AVERAGEf, 1); 1202 } else { 1203 soc_reg_field_set(unit, config_reg, &val, CAP_AVERAGEf, 0); 1204 } 1205 if (flags & BCM_COSQ_DISCARD_ENABLE) { 1206 soc_reg_field_set(unit, config_reg, &val, ENABLEf, 1); 1207 } else { 1208 soc_reg_field_set(unit, config_reg, &val, ENABLEf, 0); 1209 } 1210 SOC_IF_ERROR_RETURN(soc_reg32_write(unit, addr, val)); 1211 return BCM_E_NONE; 1212 } 1213 1214 STATIC int 1215 _bcm_tr2_cosq_discard_cap_enable_get(int unit, bcm_port_t port, 1216 bcm_cos_queue_t cosq, soc_reg_t config_reg, 1217 uint32 *flags) 1218 { 1219 uint32 val, addr; 1220 1221 addr = soc_reg_addr(unit, config_reg, port, cosq); 1222 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &val)); 1223 1224 if (soc_reg_field_get(unit, config_reg, val, CAP_AVERAGEf)) { 1225 *flags |= BCM_COSQ_DISCARD_CAP_AVERAGE; 1226 } 1227 if (soc_reg_field_get(unit, config_reg, val, ENABLEf)) { 1228 *flags |= BCM_COSQ_DISCARD_ENABLE; 1229 } 1230 return BCM_E_NONE; 1231 } 1232 1233 int 1234 bcm_tr2_cosq_discard_set(int unit, uint32 flags) 1235 { 1236 bcm_port_t port; 1237 bcm_cos_queue_t cosq; 1238 soc_reg_t config_reg = WREDCONFIG_PACKETr; 1239 1240 if (flags & ~(BCM_COSQ_DISCARD_CAP_AVERAGE | 1241 BCM_COSQ_DISCARD_ENABLE)) { 1242 return BCM_E_PARAM; 1243 } 1244 1245 PBMP_ALL_ITER(unit, port) { 1246 if (IS_CPU_PORT(unit, port)) { 1247 continue; 1248 } 1249 for (cosq = 0; cosq < 8; cosq++) { 1250 BCM_IF_ERROR_RETURN 1251 (_bcm_tr2_cosq_discard_cap_enable_set(unit, port, cosq, 1252 config_reg, flags)); 1253 } 1254 if (SOC_PBMP_MEMBER(_tr2_cosq_24q_ports[unit], port)) { 1255 for (cosq = 8; cosq < 24; cosq++) { 1256 BCM_IF_ERROR_RETURN 1257 (_bcm_tr2_cosq_discard_cap_enable_set(unit, port, cosq, 1258 config_reg, flags)); 1259 } 1260 } 1261 } 1262 return BCM_E_NONE; 1263 } 1264 1265 int 1266 bcm_tr2_cosq_discard_get(int unit, uint32 *flags) 1267 { 1268 int rv = BCM_E_NONE; 1269 bcm_port_t port; 1270 soc_reg_t config_reg = WREDCONFIG_PACKETr; 1271 1272 PBMP_ALL_ITER(unit, port) { 1273 if (IS_CPU_PORT(unit, port)) { 1274 continue; 1275 } 1276 *flags = 0; 1277 rv = _bcm_tr2_cosq_discard_cap_enable_get(unit, port, 0, 1278 config_reg, flags); 1279 break; 1280 } 1281 return rv; 1282 } 1283 1284 /* 1285 * Convert HW drop probability to percent value 1286 */ 1287 STATIC int 1288 _bcm_tr2_hw_drop_prob_to_percent[] = { 1289 0, /* 0 */ 1290 1, /* 1 */ 1291 2, /* 2 */ 1292 3, /* 3 */ 1293 4, /* 4 */ 1294 5, /* 5 */ 1295 6, /* 6 */ 1296 7, /* 7 */ 1297 8, /* 8 */ 1298 9, /* 9 */ 1299 10, /* 10 */ 1300 25, /* 11 */ 1301 50, /* 12 */ 1302 75, /* 13 */ 1303 100, /* 14 */ 1304 -1 /* 15 */ 1305 }; 1306 1307 STATIC int 1308 _bcm_tr2_percent_to_drop_prob(int percent) { 1309 int i; 1310 1311 for (i=14; i > 0 ; i--) { 1312 if (percent >= _bcm_tr2_hw_drop_prob_to_percent[i]) { 1313 break; 1314 } 1315 } 1316 return i; 1317 } 1318 1319 STATIC int 1320 _bcm_tr2_drop_prob_to_percent(int drop_prob) { 1321 return (_bcm_tr2_hw_drop_prob_to_percent[drop_prob]); 1322 } 1323 1324 STATIC int 1325 _bcm_tr2_angle_to_packets_table[] = 1326 { 1327 /* 0.. 5 */ 16383, 5727, 2862, 1908, 1430, 1142, 1328 /* 6..11 */ 951, 814, 711, 631, 567, 514, 1329 /* 12..17 */ 470, 433, 401, 373, 348, 327, 1330 /* 18..23 */ 307, 290, 274, 260, 247, 235, 1331 /* 24..29 */ 224, 214, 205, 196, 188, 180, 1332 /* 30..35 */ 173, 166, 160, 153, 148, 142, 1333 /* 36..41 */ 137, 132, 127, 123, 119, 115, 1334 /* 42..47 */ 111, 107, 103, 100, 96, 93, 1335 /* 48..53 */ 90, 86, 83, 80, 78, 75, 1336 /* 54..59 */ 72, 70, 67, 64, 62, 60, 1337 /* 60..65 */ 57, 55, 53, 50, 48, 46, 1338 /* 66..71 */ 44, 42, 40, 38, 36, 34, 1339 /* 72..77 */ 32, 30, 28, 26, 24, 23, 1340 /* 78..83 */ 21, 19, 17, 15, 14, 12, 1341 /* 84..89 */ 10, 8, 6, 5, 3, 1, 1342 /* 90 */ 0 1343 }; 1344 1345 /* 1346 * Given a slope (angle in degrees) from 0 to 90, return 1347 * the number of packets in the range from 0% drop 1348 * probability to 100% drop probability. 1349 */ 1350 STATIC int 1351 _bcm_tr2_angle_to_packets(int angle) { 1352 return (_bcm_tr2_angle_to_packets_table[angle]); 1353 } 1354 1355 /* 1356 * Given a number of packets in the range from 0% drop probability 1357 * to 100% drop probability, return the slope (angle in degrees). 1358 */ 1359 STATIC int 1360 _bcm_tr2_packets_to_angle(int packets) { 1361 int angle; 1362 1363 for (angle = 90; angle >= 0 ; angle--) { 1364 if (packets <= _bcm_tr2_angle_to_packets_table[angle]) { 1365 break; 1366 } 1367 } 1368 return angle; 1369 } 1370 1371 STATIC int 1372 _bcm_tr2_cosq_discard_set(int unit, bcm_port_t port, uint32 flags, 1373 bcm_cos_queue_t cosq, soc_reg_t config_reg, 1374 soc_reg_t thresh_reg_green, 1375 soc_reg_t thresh_reg_yellow, 1376 soc_reg_t thresh_reg_red, 1377 soc_reg_t thresh_reg_non_tcp, 1378 uint32 min_thresh, uint32 max_thresh, 1379 int drop_probability, int gain) 1380 { 1381 uint32 val, addr; 1382 1383 if (flags & ~(BCM_COSQ_DISCARD_COLOR_GREEN | 1384 BCM_COSQ_DISCARD_COLOR_YELLOW | 1385 BCM_COSQ_DISCARD_COLOR_RED | 1386 BCM_COSQ_DISCARD_COLOR_ALL | 1387 BCM_COSQ_DISCARD_CAP_AVERAGE | 1388 BCM_COSQ_DISCARD_PACKETS | 1389 BCM_COSQ_DISCARD_BYTES | 1390 BCM_COSQ_DISCARD_ENABLE | 1391 BCM_COSQ_DISCARD_NONTCP)) { 1392 return BCM_E_PARAM; 1393 } 1394 1395 addr = soc_reg_addr(unit, config_reg, port, cosq); 1396 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &val)); 1397 1398 /* Program the weight */ 1399 soc_reg_field_set(unit, config_reg, &val, WEIGHTf, gain); 1400 1401 /* Program the drop probabilty */ 1402 if ((flags & BCM_COSQ_DISCARD_COLOR_GREEN) || 1403 ((flags & BCM_COSQ_DISCARD_COLOR_ALL) == BCM_COSQ_DISCARD_COLOR_ALL)) { 1404 soc_reg_field_set(unit, config_reg, &val, MAXDROPRATEf, 1405 _bcm_tr2_percent_to_drop_prob(drop_probability)); 1406 } 1407 if ((flags & BCM_COSQ_DISCARD_COLOR_YELLOW) || 1408 ((flags & BCM_COSQ_DISCARD_COLOR_ALL) == BCM_COSQ_DISCARD_COLOR_ALL)) { 1409 soc_reg_field_set(unit, config_reg, &val, YELLOW_MAXDROPRATEf, 1410 _bcm_tr2_percent_to_drop_prob(drop_probability)); 1411 } 1412 if ((flags & BCM_COSQ_DISCARD_COLOR_RED) || 1413 ((flags & BCM_COSQ_DISCARD_COLOR_ALL) == BCM_COSQ_DISCARD_COLOR_ALL)) { 1414 soc_reg_field_set(unit, config_reg, &val, RED_MAXDROPRATEf, 1415 _bcm_tr2_percent_to_drop_prob(drop_probability)); 1416 } 1417 if (flags & BCM_COSQ_DISCARD_NONTCP) { 1418 soc_reg_field_set(unit, config_reg, &val, NONTCP_MAXDROPRATEf, 1419 _bcm_tr2_percent_to_drop_prob(drop_probability)); 1420 } 1421 SOC_IF_ERROR_RETURN(soc_reg32_write(unit, addr, val)); 1422 1423 /* Program the min and max thresholds */ 1424 if ((flags & BCM_COSQ_DISCARD_COLOR_GREEN) || 1425 ((flags & BCM_COSQ_DISCARD_COLOR_ALL) == BCM_COSQ_DISCARD_COLOR_ALL)) { 1426 addr = soc_reg_addr(unit, thresh_reg_green, port, cosq); 1427 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &val)); 1428 soc_reg_field_set(unit, thresh_reg_green, &val, DROPSTARTPOINTf, 1429 min_thresh); 1430 soc_reg_field_set(unit, thresh_reg_green, &val, DROPENDPOINTf, 1431 max_thresh); 1432 SOC_IF_ERROR_RETURN(soc_reg32_write(unit, addr, val)); 1433 } 1434 if ((flags & BCM_COSQ_DISCARD_COLOR_YELLOW) || 1435 ((flags & BCM_COSQ_DISCARD_COLOR_ALL) == BCM_COSQ_DISCARD_COLOR_ALL)) { 1436 addr = soc_reg_addr(unit, thresh_reg_yellow, port, cosq); 1437 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &val)); 1438 soc_reg_field_set(unit, thresh_reg_yellow, &val, 1439 YELLOW_DROPSTARTPOINTf, min_thresh); 1440 soc_reg_field_set(unit, thresh_reg_yellow, &val, 1441 YELLOW_DROPENDPOINTf, max_thresh); 1442 SOC_IF_ERROR_RETURN(soc_reg32_write(unit, addr, val)); 1443 } 1444 if ((flags & BCM_COSQ_DISCARD_COLOR_RED) || 1445 ((flags & BCM_COSQ_DISCARD_COLOR_ALL) == BCM_COSQ_DISCARD_COLOR_ALL)) { 1446 addr = soc_reg_addr(unit, thresh_reg_red, port, cosq); 1447 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &val)); 1448 soc_reg_field_set(unit, thresh_reg_red, &val, 1449 RED_DROPSTARTPOINTf, min_thresh); 1450 soc_reg_field_set(unit, thresh_reg_red, &val, 1451 RED_DROPENDPOINTf, max_thresh); 1452 SOC_IF_ERROR_RETURN(soc_reg32_write(unit, addr, val)); 1453 } 1454 if (flags & BCM_COSQ_DISCARD_NONTCP) { 1455 addr = soc_reg_addr(unit, thresh_reg_non_tcp, port, cosq); 1456 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &val)); 1457 soc_reg_field_set(unit, thresh_reg_non_tcp, &val, 1458 NONTCP_DROPSTARTPOINTf, min_thresh); 1459 soc_reg_field_set(unit, thresh_reg_non_tcp, &val, 1460 NONTCP_DROPENDPOINTf, max_thresh); 1461 SOC_IF_ERROR_RETURN(soc_reg32_write(unit, addr, val)); 1462 } 1463 1464 return BCM_E_NONE; 1465 } 1466 1467 STATIC int 1468 _bcm_tr2_cosq_discard_get(int unit, bcm_port_t port, uint32 flags, 1469 bcm_cos_queue_t cosq, soc_reg_t config_reg, 1470 soc_reg_t thresh_reg_green, 1471 soc_reg_t thresh_reg_yellow, 1472 soc_reg_t thresh_reg_red, 1473 soc_reg_t thresh_reg_non_tcp, 1474 uint32 *min_thresh, uint32 *max_thresh, 1475 int *drop_probability, int *gain) 1476 { 1477 uint32 val, addr, drop_rate; 1478 1479 addr = soc_reg_addr(unit, config_reg, port, cosq); 1480 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &val)); 1481 1482 /* Get the weight */ 1483 *gain = soc_reg_field_get(unit, config_reg, val, WEIGHTf); 1484 1485 /* Get the drop probabilty */ 1486 if (flags & BCM_COSQ_DISCARD_COLOR_YELLOW) { 1487 drop_rate = soc_reg_field_get(unit, config_reg, val, 1488 YELLOW_MAXDROPRATEf); 1489 } else if (flags & BCM_COSQ_DISCARD_COLOR_RED) { 1490 drop_rate = soc_reg_field_get(unit, config_reg, val, 1491 RED_MAXDROPRATEf); 1492 } else { 1493 drop_rate = soc_reg_field_get(unit, config_reg, val, 1494 MAXDROPRATEf); 1495 } 1496 *drop_probability = _bcm_tr2_drop_prob_to_percent(drop_rate); 1497 1498 /* Get the min and max thresholds */ 1499 if (flags & BCM_COSQ_DISCARD_COLOR_YELLOW) { 1500 addr = soc_reg_addr(unit, thresh_reg_yellow, port, cosq); 1501 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &val)); 1502 *min_thresh = soc_reg_field_get(unit, thresh_reg_yellow, val, 1503 YELLOW_DROPSTARTPOINTf); 1504 *max_thresh = soc_reg_field_get(unit, thresh_reg_yellow, val, 1505 YELLOW_DROPENDPOINTf); 1506 } else if (flags & BCM_COSQ_DISCARD_COLOR_RED) { 1507 addr = soc_reg_addr(unit, thresh_reg_red, port, cosq); 1508 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &val)); 1509 *min_thresh = soc_reg_field_get(unit, thresh_reg_red, val, 1510 RED_DROPSTARTPOINTf); 1511 *max_thresh = soc_reg_field_get(unit, thresh_reg_red, val, 1512 RED_DROPENDPOINTf); 1513 } else { 1514 addr = soc_reg_addr(unit, thresh_reg_green, port, cosq); 1515 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &val)); 1516 *min_thresh = soc_reg_field_get(unit, thresh_reg_green, val, 1517 DROPSTARTPOINTf); 1518 *max_thresh = soc_reg_field_get(unit, thresh_reg_green, val, 1519 DROPENDPOINTf); 1520 } 1521 return BCM_E_NONE; 1522 } 1523 1524 #define ABS(n) (((n) < 0) ? -(n) : (n)) 1525 1526 int 1527 bcm_tr2_cosq_discard_port_set(int unit, bcm_port_t port, 1528 bcm_cos_queue_t cosq, 1529 uint32 color, 1530 int drop_start, 1531 int drop_slope, 1532 int average_time) 1533 { 1534 bcm_module_t modid; 1535 bcm_port_t local_port; 1536 bcm_trunk_t trunk_id; 1537 bcm_pbmp_t pbmp; 1538 int i, gain, cosq_start, num_cosq; 1539 uint32 min_thresh, max_thresh, shared_limit; 1540 uint32 rval, bits; 1541 1542 if (!_tr2_num_port_cosq[unit]) { 1543 return BCM_E_INIT; 1544 } 1545 1546 if (drop_start < 0 || drop_start > 100 || 1547 drop_slope < 0 || drop_slope > 90) { 1548 return BCM_E_PARAM; 1549 } 1550 1551 if (BCM_GPORT_IS_SET(port)) { 1552 if (BCM_GPORT_IS_SCHEDULER(port)) { 1553 BCM_IF_ERROR_RETURN 1554 (_bcm_tr2_cosq_resolve_mod_port(unit, port, &modid, 1555 &local_port, &trunk_id)); 1556 } else { 1557 BCM_IF_ERROR_RETURN 1558 (bcm_esw_port_local_get(unit, port, &local_port)); 1559 } 1560 BCM_PBMP_PORT_SET(pbmp, local_port); 1561 } else { 1562 if (port == -1) { 1563 BCM_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit)); 1564 } else if (IS_CPU_PORT(unit, port) || !SOC_PORT_VALID(unit, port)) { 1565 return BCM_E_PORT; 1566 } else { 1567 local_port = port; 1568 BCM_PBMP_PORT_SET(pbmp, port); 1569 } 1570 } 1571 1572 if (BCM_GPORT_IS_SCHEDULER(port)) { 1573 if (_tr2_num_port_cosq[unit][local_port] == 0) { 1574 return BCM_E_NOT_FOUND; 1575 } else if (cosq < -1 || cosq >= _tr2_num_port_cosq[unit][local_port]) { 1576 return BCM_E_PARAM; 1577 } else if (cosq == -1) { 1578 cosq_start = 8; 1579 num_cosq = _tr2_num_port_cosq[unit][local_port]; 1580 } else { 1581 cosq_start = cosq + 8; 1582 num_cosq = 1; 1583 } 1584 } else { 1585 if (cosq < -1 || cosq >= _tr2_num_cosq[unit]) { 1586 return BCM_E_PARAM; 1587 } else if (cosq == -1) { 1588 cosq_start = 0; 1589 num_cosq = 8; 1590 } else { 1591 cosq_start = cosq; 1592 num_cosq = 1; 1593 } 1594 } 1595 1596 /* 1597 * average queue size is reculated every 4us, the formula is 1598 * avg_qsize(t + 1) = 1599 * avg_qsize(t) + (cur_qsize - avg_qsize(t)) / (2 ** gain) 1600 * gain = log2(average_time / 4) 1601 */ 1602 bits = (average_time / 4) & 0xffff; 1603 bits |= bits >> 1; 1604 bits |= bits >> 2; 1605 bits |= bits >> 4; 1606 bits |= bits >> 8; 1607 gain = _shr_popcount(bits); 1608 /* Don't allow negative value of gain */ 1609 if (gain) { 1610 gain -= 1; 1611 } 1612 1613 /* 1614 * per-port packet limit may be disabled. 1615 * per-port per-cos packet limit may be set to use dynamic method. 1616 * therefore drop_start percentage is based on per-device total shared 1617 * packets. 1618 */ 1619 SOC_IF_ERROR_RETURN(READ_OP_BUFFER_SHARED_LIMIT_PACKETr(unit, &rval)); 1620 shared_limit = soc_reg_field_get(unit, OP_BUFFER_SHARED_LIMIT_PACKETr, 1621 rval, OP_BUFFER_SHARED_LIMIT_PACKETf); 1622 min_thresh = drop_start * shared_limit / 100; 1623 1624 /* Calculate the max threshold. For a given slope (angle in 1625 * degrees), determine how many packets are in the range from 1626 * 0% drop probability to 100% drop probability. Add that 1627 * number to the min_treshold to the the max_threshold. 1628 */ 1629 max_thresh = min_thresh + _bcm_tr2_angle_to_packets(drop_slope); 1630 if (max_thresh > TR2_PACKET_FIELD_MAX) { 1631 max_thresh = TR2_PACKET_FIELD_MAX; 1632 } 1633 1634 BCM_PBMP_ITER(pbmp, local_port) { 1635 for (i = cosq_start; i < (cosq_start + num_cosq); i++) { 1636 BCM_IF_ERROR_RETURN 1637 (_bcm_tr2_cosq_discard_set(unit, local_port, color, i, 1638 WREDCONFIG_PACKETr, 1639 WREDPARAM_PACKETr, 1640 WREDPARAM_YELLOW_PACKETr, 1641 WREDPARAM_RED_PACKETr, 1642 WREDPARAM_NONTCP_PACKETr, 1643 min_thresh, max_thresh, 100, gain)); 1644 } 1645 } 1646 return BCM_E_NONE; 1647 } 1648 1649 int 1650 bcm_tr2_cosq_discard_port_get(int unit, bcm_port_t port, 1651 bcm_cos_queue_t cosq, 1652 uint32 color, 1653 int *drop_start, 1654 int *drop_slope, 1655 int *average_time) 1656 { 1657 bcm_module_t modid; 1658 bcm_port_t local_port; 1659 bcm_trunk_t trunk_id; 1660 bcm_pbmp_t pbmp; 1661 int gain, drop_prob; 1662 uint32 min_thresh, max_thresh, shared_limit; 1663 uint32 rval; 1664 1665 if (!_tr2_num_port_cosq[unit]) { 1666 return BCM_E_INIT; 1667 } 1668 1669 if (drop_start == NULL || drop_slope == NULL || average_time == NULL) { 1670 return BCM_E_PARAM; 1671 } 1672 1673 if (BCM_GPORT_IS_SET(port)) { 1674 if (BCM_GPORT_IS_SCHEDULER(port)) { 1675 BCM_IF_ERROR_RETURN 1676 (_bcm_tr2_cosq_resolve_mod_port(unit, port, &modid, 1677 &local_port, &trunk_id)); 1678 } else { 1679 BCM_IF_ERROR_RETURN 1680 (bcm_esw_port_local_get(unit, port, &local_port)); 1681 } 1682 BCM_PBMP_PORT_SET(pbmp, local_port); 1683 } else { 1684 if (port == -1) { 1685 BCM_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit)); 1686 } else if (IS_CPU_PORT(unit, port) || !SOC_PORT_VALID(unit, port)) { 1687 return BCM_E_PORT; 1688 } else { 1689 local_port = port; 1690 BCM_PBMP_PORT_SET(pbmp, port); 1691 } 1692 } 1693 1694 if (BCM_GPORT_IS_SCHEDULER(port)) { 1695 if (_tr2_num_port_cosq[unit][local_port] == 0) { 1696 return BCM_E_NOT_FOUND; 1697 } else if (cosq < -1 || cosq >= _tr2_num_port_cosq[unit][local_port]) { 1698 return BCM_E_PARAM; 1699 } else if (cosq == -1) { 1700 cosq = 8; 1701 } else { 1702 cosq = cosq + 8; 1703 } 1704 } else { 1705 if (cosq < -1 || cosq >= _tr2_num_cosq[unit]) { 1706 return BCM_E_PARAM; 1707 } else if (cosq == -1) { 1708 cosq = 0; 1709 } 1710 } 1711 1712 BCM_PBMP_ITER(pbmp, local_port) { 1713 BCM_IF_ERROR_RETURN 1714 (_bcm_tr2_cosq_discard_get(unit, local_port, color, cosq, 1715 WREDCONFIG_PACKETr, 1716 WREDPARAM_PACKETr, 1717 WREDPARAM_YELLOW_PACKETr, 1718 WREDPARAM_RED_PACKETr, 1719 WREDPARAM_NONTCP_PACKETr, 1720 &min_thresh, &max_thresh, &drop_prob, 1721 &gain)); 1722 1723 /* 1724 * average queue size is reculated every 4us, the formula is 1725 * avg_qsize(t + 1) = 1726 * avg_qsize(t) + (cur_qsize - avg_qsize(t)) / (2 ** gain) 1727 */ 1728 *average_time = (1 << gain) * 4; 1729 1730 /* 1731 * per-port packet limit may be disabled. 1732 * per-port per-cos packet limit may be set to use dynamic method. 1733 * therefore drop_start percentage is based on per-device total shared 1734 * packets. 1735 */ 1736 SOC_IF_ERROR_RETURN(READ_OP_BUFFER_SHARED_LIMIT_PACKETr(unit, &rval)); 1737 shared_limit = soc_reg_field_get(unit, OP_BUFFER_SHARED_LIMIT_PACKETr, 1738 rval, OP_BUFFER_SHARED_LIMIT_PACKETf); 1739 if (min_thresh >= shared_limit) { 1740 *drop_start = 100; 1741 } else { 1742 *drop_start = min_thresh * 100 / shared_limit; 1743 } 1744 1745 /* Calculate the slope using the min and max threshold. 1746 * The angle is calculated knowing drop probability at min 1747 * threshold is 0% and drop probability at max threshold is 100%. 1748 */ 1749 *drop_slope = _bcm_tr2_packets_to_angle(max_thresh - min_thresh); 1750 break; 1751 } 1752 1753 return BCM_E_NONE; 1754 } 1755 1756 STATIC int 1757 _bcm_tr2_cosq_port_sched_set(int unit, soc_reg_t config_reg, 1758 soc_reg_t weight_reg, soc_reg_t minsp_reg, 1759 bcm_port_t port, bcm_cos_queue_t start_cosq, 1760 int num_weights, const int weights[], 1761 int mode) 1762 { 1763 int t, i; 1764 uint32 cfg_addr, cosw_addr, minsp_addr, cfg, cosw, minsp; 1765 int mbits = 0; 1766 int weight_max, sel, quanta; 1767 1768 cfg_addr = soc_reg_addr(unit, config_reg, port, 0); 1769 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, cfg_addr, &cfg)); 1770 1771 switch (mode) { 1772 case BCM_COSQ_STRICT: 1773 mbits = 0; 1774 break; 1775 case BCM_COSQ_ROUND_ROBIN: 1776 mbits = 1; 1777 break; 1778 case BCM_COSQ_WEIGHTED_ROUND_ROBIN: 1779 mbits = 2; 1780 /* 1781 * All weight values must fit within 7 bits. 1782 * If weight is 0, this queue is run in strict mode, 1783 * others run in WRR mode. 1784 */ 1785 for(i = 0; i < num_weights; i++) { 1786 if (weights[i] > TR2_WRR_WEIGHT_MAX) { 1787 return BCM_E_PARAM; 1788 } 1789 } 1790 for (i = 0; i < num_weights; i++) { 1791 cosw_addr = soc_reg_addr(unit, weight_reg, port, start_cosq + i); 1792 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, cosw_addr, &cosw)); 1793 soc_reg_field_set(unit, weight_reg, &cosw, COSWEIGHTSf, 1794 weights[i]); 1795 SOC_IF_ERROR_RETURN(soc_reg32_write(unit, cosw_addr, cosw)); 1796 } 1797 break; 1798 case BCM_COSQ_DEFICIT_ROUND_ROBIN: 1799 mbits = 3; 1800 1801 weight_max = 0; 1802 for (i = 0; i < num_weights; i++) { 1803 if (weight_max < weights[i]) { 1804 weight_max = weights[i]; 1805 } 1806 } 1807 1808 for (sel = 0; sel <= 3; sel++) { 1809 if (weight_max <= TR2_DRR_WEIGHT_MAX * (1 << (sel + 1))) { 1810 break; 1811 } 1812 } 1813 if (sel > 3) { 1814 return BCM_E_PARAM; 1815 } 1816 quanta = 1 << (sel + 1); 1817 soc_reg_field_set(unit, config_reg, &cfg, MTU_QUANTA_SELECTf, sel); 1818 for (i = 0; i < num_weights; i++) { 1819 cosw_addr = soc_reg_addr(unit, weight_reg, port, start_cosq + i); 1820 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, cosw_addr, &cosw)); 1821 /* the unit of weight for WDRR is specified mtu quanta */ 1822 soc_reg_field_set(unit, weight_reg, &cosw, COSWEIGHTSf, 1823 (weights[i] + quanta - 1) / quanta); 1824 SOC_IF_ERROR_RETURN(soc_reg32_write(unit, cosw_addr, cosw)); 1825 } 1826 break; 1827 case BCM_COSQ_BOUNDED_DELAY: /* not supported in xgs */ 1828 default: 1829 return BCM_E_PARAM; 1830 } 1831 1832 if ((mode == BCM_COSQ_WEIGHTED_ROUND_ROBIN) || 1833 (mode == BCM_COSQ_DEFICIT_ROUND_ROBIN)) { 1834 /* Set strict priority bit if weight is zero */ 1835 minsp_addr = soc_reg_addr(unit, minsp_reg, port, 0); 1836 SOC_IF_ERROR_RETURN 1837 (soc_reg32_read(unit, minsp_addr, &minsp)); 1838 for(i = 0; i < num_weights; i++) { 1839 t = start_cosq + i; 1840 if (weights[i] == 0) { 1841 minsp |= (1 << t); 1842 } else { 1843 minsp &= ~(1 << t); 1844 } 1845 } 1846 SOC_IF_ERROR_RETURN 1847 (soc_reg32_write(unit, minsp_addr, minsp)); 1848 } 1849 1850 /* Program the scheduling mode */ 1851 soc_reg_field_set(unit, config_reg, &cfg, SCHEDULING_SELECTf, mbits); 1852 SOC_IF_ERROR_RETURN(soc_reg32_write(unit, cfg_addr, cfg)); 1853 1854 return BCM_E_NONE; 1855 } 1856 1857 STATIC int 1858 _bcm_tr2_cosq_port_sched_get(int unit, soc_reg_t config_reg, 1859 soc_reg_t weight_reg, bcm_port_t port, 1860 bcm_cos_queue_t start_cosq, 1861 int num_weights, int weights[], int *mode) 1862 { 1863 uint32 addr, cfg, cosw; 1864 int mbits, i; 1865 uint32 quanta; 1866 1867 addr = soc_reg_addr(unit, config_reg, port, 0); 1868 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &cfg)); 1869 mbits = soc_reg_field_get(unit, config_reg, cfg, SCHEDULING_SELECTf); 1870 1871 switch (mbits) { 1872 case 0: 1873 *mode = BCM_COSQ_STRICT; 1874 break; 1875 case 1: 1876 *mode = BCM_COSQ_ROUND_ROBIN; 1877 break; 1878 case 2: 1879 *mode = BCM_COSQ_WEIGHTED_ROUND_ROBIN; 1880 for (i = 0; i < num_weights; i++) { 1881 addr = soc_reg_addr(unit, weight_reg, port, start_cosq + i); 1882 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &cosw)); 1883 weights[i] = soc_reg_field_get(unit, weight_reg, cosw, 1884 COSWEIGHTSf); 1885 } 1886 break; 1887 case 3: 1888 *mode = BCM_COSQ_DEFICIT_ROUND_ROBIN; 1889 switch (soc_reg_field_get(unit, config_reg, cfg, MTU_QUANTA_SELECTf)) { 1890 case 0: /* quanta is 2k bytes */ 1891 quanta = 2; 1892 break; 1893 case 1: /* quanta is 4k bytes */ 1894 quanta = 4; 1895 break; 1896 case 2: /* quanta is 8k bytes */ 1897 quanta = 8; 1898 break; 1899 case 3: /* quanta is 16k bytes */ 1900 quanta = 16; 1901 break; 1902 default: 1903 return SOC_E_INTERNAL; 1904 } 1905 for (i = 0; i < num_weights; i++) { 1906 addr = soc_reg_addr(unit, weight_reg, port, start_cosq + i); 1907 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &cosw)); 1908 /* the unit of weight for WDRR is specified mtu quanta */ 1909 weights[i] = soc_reg_field_get(unit, weight_reg, cosw, 1910 COSWEIGHTSf) * quanta; 1911 } 1912 break; 1913 default: 1914 return BCM_E_INTERNAL; 1915 } 1916 1917 return BCM_E_NONE; 1918 } 1919 1920 /* 1921 * Function: 1922 * bcm_cosq_port_sched_set 1923 * Purpose: 1924 * Set up class-of-service policy and corresponding weights and delay 1925 * Parameters: 1926 * unit - StrataSwitch unit number. 1927 * pbm - port bitmap 1928 * mode - Scheduling mode, one of BCM_COSQ_xxx 1929 * weights - Weights for each COS queue 1930 * Only for BCM_COSQ_WEIGHTED_FAIR_ROUND_ROBIN mode. 1931 * For DRR Weight is specified in Kbytes 1932 * delay - This parameter is not used 1933 * Returns: 1934 * BCM_E_XXX 1935 */ 1936 1937 int 1938 bcm_tr2_cosq_port_sched_set(int unit, bcm_pbmp_t pbm, 1939 int mode, const int weights[], int delay) 1940 { 1941 bcm_port_t port; 1942 int i, max_weight; 1943 1944 mbcm_driver[unit]->mbcm_cosq_sched_weight_max_get(unit, mode, &max_weight); 1945 if((mode != BCM_COSQ_STRICT) && (mode != BCM_COSQ_ROUND_ROBIN) && 1946 (max_weight != BCM_COSQ_WEIGHT_UNLIMITED)) { 1947 for(i = 0; i < NUM_COS(unit); i++) { 1948 if((weights[i] < 0) || (weights[i] > max_weight)) { 1949 return BCM_E_PARAM; 1950 } 1951 } 1952 } 1953 1954 PBMP_ITER(pbm, port) { 1955 BCM_IF_ERROR_RETURN 1956 (_bcm_tr2_cosq_port_sched_set(unit, 1957 ESCONFIGr, COSWEIGHTSr, MINSPCONFIGr, 1958 port, 0, 8, weights, mode)); 1959 } 1960 return BCM_E_NONE; 1961 } 1962 1963 /* 1964 * Function: 1965 * bcm_cosq_port_sched_get 1966 * Purpose: 1967 * Retrieve class-of-service policy and corresponding weights and delay 1968 * Parameters: 1969 * unit - StrataSwitch unit number. 1970 * pbm - port bitmap 1971 * mode - (output) Scheduling mode, one of BCM_COSQ_xxx 1972 * weights - (output) Weights for each COS queue 1973 * Only for BCM_COSQ_WEIGHTED_ROUND_ROBIN and 1974 * BCM_COSQ_DEFICIT_ROUND_ROBIN mode. 1975 * For DRR Weight is specified in Kbytes 1976 * delay - This parameter is not used 1977 * Returns: 1978 * BCM_E_XXX 1979 * Notes: 1980 * Actually just returns data for the first port in the bitmap 1981 */ 1982 1983 int 1984 bcm_tr2_cosq_port_sched_get(int unit, bcm_pbmp_t pbm, 1985 int *mode, int weights[], int *delay) 1986 { 1987 bcm_port_t port; 1988 1989 PBMP_ITER(pbm, port) { 1990 BCM_IF_ERROR_RETURN 1991 (_bcm_tr2_cosq_port_sched_get(unit, ESCONFIGr, COSWEIGHTSr, 1992 port, 0, 8, weights, mode)); 1993 break; 1994 } 1995 return BCM_E_NONE; 1996 } 1997 1998 /* 1999 * Function: 2000 * bcm_cosq_gport_add 2001 * Purpose: 2002 * 2003 * Parameters: 2004 * unit - (IN) Unit number. 2005 * port - (IN) Physical port. 2006 * numq - (IN) Number of COS queues. 2007 * flags - (IN) Flags. 2008 * gport - (IN/OUT) GPORT ID. 2009 * Returns: 2010 * BCM_E_XXX 2011 */ 2012 int 2013 bcm_tr2_cosq_gport_add(int unit, bcm_gport_t port, int numq, 2014 uint32 flags, bcm_gport_t *gport) 2015 { 2016 bcm_module_t modid, mod_out; 2017 bcm_port_t local_port, port_out; 2018 bcm_trunk_t trunk_id; 2019 int gport_id; 2020 2021 if ((numq <= 0) || (numq > 16) || 2022 (!BCM_GPORT_IS_LOCAL(port) && !BCM_GPORT_IS_MODPORT(port))) { 2023 return BCM_E_PARAM; 2024 } 2025 if (flags & (BCM_COSQ_GPORT_WITH_ID | BCM_COSQ_GPORT_OVERLAY | 2026 BCM_COSQ_GPORT_UCAST_QUEUE_GROUP | BCM_COSQ_GPORT_MCAST_QUEUE | 2027 BCM_COSQ_GPORT_MCAST_QUEUE_GROUP | BCM_COSQ_GPORT_SUBSCRIBER | 2028 BCM_COSQ_GPORT_EGRESS_GROUP | BCM_COSQ_GPORT_DISABLE | 2029 BCM_COSQ_GPORT_CALENDAR)) { 2030 return BCM_E_UNAVAIL; 2031 } 2032 2033 BCM_IF_ERROR_RETURN 2034 (_bcm_tr2_cosq_resolve_mod_port(unit, port, &modid, 2035 &local_port, &trunk_id)); 2036 2037 /* Verify that the specified port is for my modid and that 2038 * it is capable of hierarchical queueing. 2039 */ 2040 if (!_tr2_num_port_cosq[unit]) { 2041 return BCM_E_INIT; 2042 } else if (!SOC_PBMP_MEMBER(_tr2_cosq_24q_ports[unit], local_port)) { 2043 return BCM_E_PORT; 2044 } else if (_tr2_num_port_cosq[unit][local_port]) { 2045 return BCM_E_EXISTS; 2046 } 2047 /* Call delete routine to init HW settings */ 2048 BCM_IF_ERROR_RETURN (_bcm_tr2_cosq_gport_delete(unit, local_port)); 2049 2050 _tr2_num_port_cosq[unit][local_port] = numq; 2051 2052 /* The GPORT ID for SCHEDULER is the modid/port from application 2053 * space. This allows the GPORT ID to be used on remote module 2054 * API calls. Convert from local space to application space. 2055 */ 2056 BCM_IF_ERROR_RETURN 2057 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET, 2058 modid, local_port, &mod_out, &port_out)); 2059 gport_id = (mod_out << 8) | port_out; 2060 BCM_GPORT_SCHEDULER_SET(*gport, gport_id); 2061 return BCM_E_NONE; 2062 } 2063 2064 STATIC int 2065 _bcm_tr2_cosq_gport_delete(int unit, bcm_port_t port) 2066 { 2067 int cosq, weights[16]; 2068 uint32 val; 2069 2070 /* Detach from physical port */ 2071 BCM_IF_ERROR_RETURN 2072 (soc_reg_field32_modify(unit, COS_MODEr, port, SELECTf, 0x0)); 2073 BCM_IF_ERROR_RETURN 2074 (soc_reg_field32_modify(unit, ING_COS_MODEr, port, SELECTf, 0x0)); 2075 2076 /* Clear bandwidth of all Stage1 COSQs */ 2077 for (cosq = 8; cosq < 24; cosq++) { 2078 BCM_IF_ERROR_RETURN 2079 (bcm_tr2_cosq_port_bandwidth_set(unit, port, cosq, 0, 0, 0, 0)); 2080 } 2081 2082 /* Clear bandwidth of S1 output queue */ 2083 cosq = 24; 2084 BCM_IF_ERROR_RETURN 2085 (bcm_tr2_cosq_port_bandwidth_set(unit, port, cosq, 0, 0, 0, 0)); 2086 2087 /* Clear weights of all Stage1 COSQs */ 2088 for (cosq = 0; cosq < 16; cosq++) { 2089 weights[cosq] = 0; 2090 } 2091 BCM_IF_ERROR_RETURN 2092 (_bcm_tr2_cosq_port_sched_set(unit, S1V_CONFIGr, S1V_COSWEIGHTSr, 2093 S1V_MINSPCONFIGr, port, 0, 16, 2094 weights, BCM_COSQ_WEIGHTED_ROUND_ROBIN)); 2095 2096 /* Clear weight for S1 output queue */ 2097 cosq = 8; 2098 BCM_IF_ERROR_RETURN(READ_COSWEIGHTSr(unit, port, cosq, &val)); 2099 soc_reg_field_set(unit, COSWEIGHTSr, &val, COSWEIGHTSf, 0); 2100 BCM_IF_ERROR_RETURN(WRITE_COSWEIGHTSr(unit, port, cosq, val)); 2101 2102 /* Clear discard settings for all Stage1 COSQs */ 2103 for (cosq = 8; cosq < 24; cosq++) { 2104 BCM_IF_ERROR_RETURN 2105 (_bcm_tr2_cosq_discard_set(unit, port, 2106 BCM_COSQ_DISCARD_COLOR_ALL | 2107 BCM_COSQ_DISCARD_NONTCP, cosq, 2108 WREDCONFIG_PACKETr, 2109 WREDPARAM_PACKETr, 2110 WREDPARAM_YELLOW_PACKETr, 2111 WREDPARAM_RED_PACKETr, 2112 WREDPARAM_NONTCP_PACKETr, 2113 TR2_PACKET_FIELD_MAX, 2114 TR2_PACKET_FIELD_MAX, 100, 0)); 2115 } 2116 2117 _tr2_num_port_cosq[unit][port] = 0; 2118 2119 return BCM_E_NONE; 2120 } 2121 2122 /* 2123 * Function: 2124 * bcm_cosq_gport_delete 2125 * Purpose: 2126 * 2127 * Parameters: 2128 * unit - (IN) Unit number. 2129 * gport - (IN) GPORT ID. 2130 * Returns: 2131 * BCM_E_XXX 2132 */ 2133 int 2134 bcm_tr2_cosq_gport_delete(int unit, bcm_gport_t gport) 2135 { 2136 bcm_module_t modid; 2137 bcm_port_t local_port; 2138 bcm_trunk_t trunk_id; 2139 2140 BCM_IF_ERROR_RETURN 2141 (_bcm_tr2_cosq_resolve_mod_port(unit, gport, &modid, 2142 &local_port, &trunk_id)); 2143 if (BCM_GPORT_IS_SCHEDULER(gport)) { 2144 if (!_tr2_num_port_cosq[unit]) { 2145 return BCM_E_INIT; 2146 } else if (_tr2_num_port_cosq[unit][local_port] == 0) { 2147 return BCM_E_NOT_FOUND; 2148 } 2149 } else if(BCM_GPORT_IS_LOCAL(gport) || 2150 BCM_GPORT_IS_MODPORT(gport)) { 2151 if (!_tr2_num_port_cosq[unit]) { 2152 return BCM_E_INIT; 2153 } 2154 } else { 2155 return BCM_E_PARAM; 2156 } 2157 2158 BCM_IF_ERROR_RETURN (_bcm_tr2_cosq_gport_delete(unit, local_port)); 2159 return BCM_E_NONE; 2160 } 2161 2162 /* 2163 * Function: 2164 * bcm_cosq_gport_traverse 2165 * Purpose: 2166 * Walks through the valid COSQ GPORTs and calls 2167 * the user supplied callback function for each entry. 2168 * Parameters: 2169 * unit - (IN) bcm device. 2170 * trav_fn - (IN) Callback function. 2171 * user_data - (IN) User data to be passed to callback function. 2172 * Returns: 2173 * BCM_E_NONE - Success. 2174 * BCM_E_XXX 2175 */ 2176 int 2177 bcm_tr2_cosq_gport_traverse(int unit, bcm_cosq_gport_traverse_cb cb, 2178 void *user_data) 2179 { 2180 bcm_module_t my_modid, mod_out; 2181 bcm_port_t port, port_out; 2182 bcm_gport_t gport, sched_gport; 2183 int gport_id; 2184 uint32 flags = BCM_COSQ_GPORT_SCHEDULER; 2185 int rv = SOC_E_NONE; 2186 2187 if (_tr2_num_port_cosq[unit]) { 2188 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &my_modid)); 2189 BCM_PBMP_ITER(_tr2_cosq_24q_ports[unit], port) { 2190 if (_tr2_num_port_cosq[unit][port]) { 2191 2192 /* Construct physical port GPORT ID */ 2193 BCM_IF_ERROR_RETURN 2194 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET, 2195 my_modid, port, &mod_out, &port_out)); 2196 BCM_GPORT_MODPORT_SET(gport, mod_out, port_out); 2197 2198 /* Construct scheduler GPORT ID */ 2199 gport_id = (mod_out << 8) | port_out; 2200 BCM_GPORT_SCHEDULER_SET(sched_gport, gport_id); 2201 2202 /* Call application call-back */ 2203 rv = cb(unit, gport, _tr2_num_port_cosq[unit][port], 2204 flags, sched_gport, user_data); 2205 if (BCM_FAILURE(rv)) { 2206 #ifdef BCM_CB_ABORT_ON_ERR 2207 if (SOC_CB_ABORT_ON_ERR(unit)) { 2208 return rv; 2209 } 2210 #endif 2211 } 2212 } 2213 } 2214 } else { 2215 return BCM_E_INIT; 2216 } 2217 return BCM_E_NONE; 2218 } 2219 2220 STATIC int 2221 _bcm_tr2_cosq_gport_bandwidth_port_resolve(int unit, bcm_gport_t gport, 2222 bcm_cos_queue_t cosq, 2223 bcm_port_t *local_port, 2224 bcm_cos_queue_t *cosq_start, 2225 bcm_cos_queue_t *cosq_end) 2226 { 2227 bcm_module_t modid; 2228 bcm_trunk_t trunk_id; 2229 2230 if (BCM_GPORT_IS_SET(gport)) { 2231 BCM_IF_ERROR_RETURN 2232 (_bcm_tr2_cosq_resolve_mod_port(unit, gport, &modid, 2233 local_port, &trunk_id)); 2234 } else { 2235 if (!SOC_PORT_VALID(unit, gport)) { 2236 return BCM_E_PORT; 2237 } 2238 *local_port = gport; 2239 } 2240 2241 if (!_tr2_num_port_cosq[unit]) { 2242 return BCM_E_INIT; 2243 } 2244 2245 if (BCM_GPORT_IS_SCHEDULER(gport)) { 2246 if (_tr2_num_port_cosq[unit][*local_port] == 0) { 2247 return BCM_E_NOT_FOUND; 2248 } else if (cosq < 0) { 2249 *cosq_start = 8; 2250 *cosq_end = 23; 2251 } else if (cosq >= _tr2_num_port_cosq[unit][*local_port]) { 2252 return BCM_E_PARAM; 2253 } else { 2254 *cosq_start = *cosq_end = (cosq + 8); 2255 } 2256 } else if (cosq == TR2_SCHEDULER_COSQ) { 2257 if (!SOC_PBMP_MEMBER(_tr2_cosq_24q_ports[unit], *local_port)) { 2258 return BCM_E_PORT; 2259 } 2260 /* Output of S1 scheduler is configured using register offset 24 */ 2261 *cosq_start = *cosq_end = 24; 2262 } else { 2263 if (IS_CPU_PORT(unit, *local_port)) { 2264 if (cosq >= NUM_CPU_COSQ(unit)) { 2265 return BCM_E_PARAM; 2266 } else if (cosq < 0) { 2267 *cosq_start = 0; 2268 *cosq_end = NUM_CPU_COSQ(unit) - 1 ; 2269 } else { 2270 *cosq_start = *cosq_end = cosq; 2271 } 2272 } else { 2273 if (cosq >= _tr2_num_cosq[unit]) { 2274 return BCM_E_PARAM; 2275 } else if (cosq < 0) { 2276 *cosq_start = 0; 2277 *cosq_end = 7; 2278 } else { 2279 *cosq_start = *cosq_end = cosq; 2280 } 2281 } 2282 } 2283 return BCM_E_NONE; 2284 } 2285 2286 /* 2287 * Function: 2288 * bcm_cosq_gport_bandwidth_set 2289 * Purpose: 2290 * 2291 * Parameters: 2292 * unit - (IN) Unit number. 2293 * gport - (IN) GPORT ID. 2294 * cosq - (IN) COS queue to configure, -1 for all COS queues. 2295 * kbits_sec_min - (IN) minimum bandwidth, kbits/sec. 2296 * kbits_sec_max - (IN) maximum bandwidth, kbits/sec. 2297 * flags - (IN) BCM_COSQ_BW_* 2298 * Returns: 2299 * BCM_E_XXX 2300 */ 2301 int 2302 bcm_tr2_cosq_gport_bandwidth_set(int unit, bcm_gport_t gport, 2303 bcm_cos_queue_t cosq, uint32 kbits_sec_min, 2304 uint32 kbits_sec_max, uint32 flags) 2305 { 2306 bcm_port_t local_port; 2307 int i; 2308 bcm_cos_queue_t cosq_start = 0, cosq_end = 0; 2309 2310 BCM_IF_ERROR_RETURN 2311 (_bcm_tr2_cosq_gport_bandwidth_port_resolve(unit, gport, cosq, 2312 &local_port, 2313 &cosq_start, &cosq_end)); 2314 2315 flags &= ~_BCM_XGS_METER_FLAG_PACKET_MODE; 2316 for (i = cosq_start; i <= cosq_end; i++) { 2317 BCM_IF_ERROR_RETURN 2318 (bcm_tr2_cosq_port_bandwidth_set(unit, local_port, i, 2319 kbits_sec_min, 2320 kbits_sec_max, 2321 kbits_sec_max, 2322 flags)); 2323 } 2324 return BCM_E_NONE; 2325 } 2326 2327 /* 2328 * Function: 2329 * bcm_cosq_gport_bandwidth_get 2330 * Purpose: 2331 * 2332 * Parameters: 2333 * unit - (IN) Unit number. 2334 * gport - (IN) GPORT ID. 2335 * cosq - (IN) COS queue to configure, -1 for all COS queues. 2336 * kbits_sec_min - (OUT) minimum bandwidth, kbits/sec. 2337 * kbits_sec_max - (OUT) maximum bandwidth, kbits/sec. 2338 * flags - (OUT) BCM_COSQ_BW_* 2339 * Returns: 2340 * BCM_E_XXX 2341 */ 2342 int 2343 bcm_tr2_cosq_gport_bandwidth_get(int unit, bcm_gport_t gport, 2344 bcm_cos_queue_t cosq, uint32 *kbits_sec_min, 2345 uint32 *kbits_sec_max, uint32 *flags) 2346 { 2347 bcm_port_t local_port; 2348 bcm_cos_queue_t cosq_start = 0, cosq_end = 0; 2349 uint32 kbits_sec_burst; /* Dummy variable */ 2350 2351 BCM_IF_ERROR_RETURN 2352 (_bcm_tr2_cosq_gport_bandwidth_port_resolve(unit, gport, cosq, 2353 &local_port, 2354 &cosq_start, &cosq_end)); 2355 *kbits_sec_min = *kbits_sec_max = *flags = 0; 2356 2357 BCM_IF_ERROR_RETURN 2358 (bcm_tr2_cosq_port_bandwidth_get(unit, local_port, cosq_start, 2359 kbits_sec_min, kbits_sec_max, 2360 &kbits_sec_burst, flags)); 2361 return BCM_E_NONE; 2362 } 2363 2364 /* 2365 * Function: 2366 * bcm_tr2_cosq_gport_bandwidth_burst_set 2367 * Purpose: 2368 * 2369 * Parameters: 2370 * unit - (IN) Unit number. 2371 * gport - (IN) GPORT ID. 2372 * cosq - (IN) COS queue to configure, -1 for all COS queues. 2373 * kbits_burst_min - (IN) minimum burst, kbits. 2374 * kbits_burst_max - (IN) maximum burst, kbits. 2375 * Returns: 2376 * BCM_E_XXX 2377 */ 2378 int 2379 bcm_tr2_cosq_gport_bandwidth_burst_set(int unit, bcm_gport_t gport, 2380 bcm_cos_queue_t cosq, 2381 uint32 kbits_burst_min, 2382 uint32 kbits_burst_max) 2383 { 2384 bcm_port_t local_port, port; 2385 int i; 2386 bcm_cos_queue_t cosq_start = 0, cosq_end = 0; 2387 uint32 kbits_sec_min, kbits_sec_max, flags = 0; 2388 uint32 kbits_sec_burst; /* Dummy variable */ 2389 2390 if (gport < 0) { 2391 PBMP_ALL_ITER(unit, port) { 2392 BCM_IF_ERROR_RETURN 2393 (_bcm_tr2_cosq_gport_bandwidth_port_resolve(unit, port, cosq, 2394 &local_port, 2395 &cosq_start, &cosq_end)); 2396 for (i = cosq_start; i <= cosq_end; i++) { 2397 BCM_IF_ERROR_RETURN 2398 (_bcm_tr2_cosq_bucket_get(unit, local_port, i, 2399 &kbits_sec_min, &kbits_sec_max, 2400 &kbits_sec_burst, &kbits_sec_burst, 2401 &flags)); 2402 BCM_IF_ERROR_RETURN 2403 (_bcm_tr2_cosq_bucket_set(unit, local_port, i, 2404 kbits_sec_min, 2405 kbits_sec_max, 2406 kbits_burst_min, 2407 kbits_burst_max, 2408 flags)); 2409 } 2410 } 2411 return BCM_E_NONE; 2412 } 2413 2414 BCM_IF_ERROR_RETURN 2415 (_bcm_tr2_cosq_gport_bandwidth_port_resolve(unit, gport, cosq, 2416 &local_port, 2417 &cosq_start, &cosq_end)); 2418 2419 for (i = cosq_start; i <= cosq_end; i++) { 2420 BCM_IF_ERROR_RETURN 2421 (_bcm_tr2_cosq_bucket_get(unit, local_port, i, 2422 &kbits_sec_min, &kbits_sec_max, 2423 &kbits_sec_burst, &kbits_sec_burst, &flags)); 2424 BCM_IF_ERROR_RETURN 2425 (_bcm_tr2_cosq_bucket_set(unit, local_port, i, 2426 kbits_sec_min, 2427 kbits_sec_max, 2428 kbits_burst_min, 2429 kbits_burst_max, 2430 flags)); 2431 } 2432 return BCM_E_NONE; 2433 } 2434 2435 /* 2436 * Function: 2437 * bcm_tr2_cosq_gport_bandwidth_burst_get 2438 * Purpose: 2439 * 2440 * Parameters: 2441 * unit - (IN) Unit number. 2442 * gport - (IN) GPORT ID. 2443 * cosq - (IN) COS queue to configure, -1 for all COS queues. 2444 * kbits_burst_min - (OUT) minimum burst, kbits. 2445 * kbits_burst_max - (OUT) maximum burst, kbits. 2446 * Returns: 2447 * BCM_E_XXX 2448 */ 2449 int 2450 bcm_tr2_cosq_gport_bandwidth_burst_get(int unit, bcm_gport_t gport, 2451 bcm_cos_queue_t cosq, 2452 uint32 *kbits_burst_min, 2453 uint32 *kbits_burst_max) 2454 { 2455 bcm_port_t local_port, port; 2456 bcm_cos_queue_t cosq_start = 0, cosq_end = 0; 2457 uint32 kbits_sec_min, kbits_sec_max, flags; /* Dummy variables */ 2458 2459 if (gport < 0) { 2460 port = SOC_PORT_MIN(unit,all); 2461 2462 BCM_IF_ERROR_RETURN 2463 (_bcm_tr2_cosq_gport_bandwidth_port_resolve(unit, port, cosq, 2464 &local_port, 2465 &cosq_start, &cosq_end)); 2466 } else { 2467 BCM_IF_ERROR_RETURN 2468 (_bcm_tr2_cosq_gport_bandwidth_port_resolve(unit, gport, cosq, 2469 &local_port, 2470 &cosq_start, &cosq_end)); 2471 } 2472 2473 kbits_sec_min = kbits_sec_max = flags = 0; 2474 2475 BCM_IF_ERROR_RETURN 2476 (_bcm_tr2_cosq_bucket_get(unit, local_port, cosq_start, 2477 &kbits_sec_min, &kbits_sec_max, 2478 kbits_burst_min, kbits_burst_max, &flags)); 2479 return BCM_E_NONE; 2480 } 2481 2482 /* 2483 * Function: 2484 * bcm_cosq_gport_sched_set 2485 * Purpose: 2486 * 2487 * Parameters: 2488 * unit - (IN) Unit number. 2489 * gport - (IN) GPORT ID. 2490 * cosq - (IN) COS queue to configure, -1 for all COS queues. 2491 * mode - (IN) Scheduling mode, one of BCM_COSQ_xxx 2492 * weight - (IN) Weight for the specified COS queue(s) 2493 * Unused if mode is BCM_COSQ_STRICT. 2494 * Returns: 2495 * BCM_E_XXX 2496 */ 2497 int 2498 bcm_tr2_cosq_gport_sched_set(int unit, bcm_gport_t gport, 2499 bcm_cos_queue_t cosq, int mode, int weight) 2500 { 2501 bcm_module_t modid; 2502 bcm_port_t local_port; 2503 bcm_trunk_t trunk_id; 2504 int i; 2505 bcm_cos_queue_t cosq_start = 0; 2506 int num_weights = 1, weights[16]; 2507 soc_reg_t config_reg = ESCONFIGr; 2508 soc_reg_t weight_reg = COSWEIGHTSr; 2509 soc_reg_t minsp_reg = MINSPCONFIGr; 2510 2511 BCM_IF_ERROR_RETURN 2512 (_bcm_tr2_cosq_resolve_mod_port(unit, gport, &modid, 2513 &local_port, &trunk_id)); 2514 2515 if (!_tr2_num_port_cosq[unit]) { 2516 return BCM_E_INIT; 2517 } 2518 if (BCM_GPORT_IS_SCHEDULER(gport)) { 2519 if (_tr2_num_port_cosq[unit][local_port] == 0) { 2520 return BCM_E_NOT_FOUND; 2521 } else if (cosq >= _tr2_num_port_cosq[unit][local_port]) { 2522 return BCM_E_PARAM; 2523 } else if (cosq < 0) { 2524 cosq_start = 0; 2525 num_weights = 16; 2526 for (i = 0; i < num_weights; i++) { 2527 if (i < _tr2_num_port_cosq[unit][local_port]) { 2528 weights[i] = weight; 2529 } else { 2530 weights[i] = 0; 2531 } 2532 } 2533 } else { 2534 cosq_start = cosq; 2535 num_weights = 1; 2536 weights[0] = weight; 2537 } 2538 config_reg = S1V_CONFIGr; 2539 weight_reg = S1V_COSWEIGHTSr; 2540 minsp_reg = S1V_MINSPCONFIGr; 2541 } else if (cosq == TR2_SCHEDULER_COSQ) { 2542 if (!SOC_PBMP_MEMBER(_tr2_cosq_24q_ports[unit], local_port)) { 2543 return BCM_E_PORT; 2544 } 2545 /* Weight for output of S1 scheduler is configured using offset 8 2546 * of COSWEIGHTS register. 2547 */ 2548 cosq_start = 8; 2549 num_weights = 1; 2550 weights[0] = weight; 2551 } else { 2552 if (cosq >= _tr2_num_cosq[unit]) { 2553 return BCM_E_PARAM; 2554 } else if (cosq < 0) { 2555 cosq_start = 0; 2556 num_weights = 8; 2557 for (i = 0; i < num_weights; i++) { 2558 if (i < _tr2_num_cosq[unit]) { 2559 weights[i] = weight; 2560 } else { 2561 weights[i] = 0; 2562 } 2563 } 2564 } else { 2565 cosq_start = cosq; 2566 num_weights = 1; 2567 weights[0] = weight; 2568 } 2569 } 2570 2571 BCM_IF_ERROR_RETURN 2572 (_bcm_tr2_cosq_port_sched_set(unit, config_reg, weight_reg, minsp_reg, 2573 local_port, cosq_start, num_weights, 2574 weights, mode)); 2575 return BCM_E_NONE; 2576 } 2577 2578 /* 2579 * Function: 2580 * bcm_cosq_gport_sched_get 2581 * Purpose: 2582 * 2583 * Parameters: 2584 * unit - (IN) Unit number. 2585 * gport - (IN) GPORT ID. 2586 * cosq - (IN) COS queue 2587 * mode - (OUT) Scheduling mode, one of BCM_COSQ_xxx 2588 * weight - (OUT) Weight for the specified COS queue(s) 2589 * Unused if mode is BCM_COSQ_STRICT. 2590 * Returns: 2591 * BCM_E_XXX 2592 */ 2593 int 2594 bcm_tr2_cosq_gport_sched_get(int unit, bcm_gport_t gport, 2595 bcm_cos_queue_t cosq, int *mode, int *weight) 2596 { 2597 bcm_module_t modid; 2598 bcm_port_t local_port; 2599 bcm_trunk_t trunk_id; 2600 soc_reg_t config_reg = ESCONFIGr; 2601 soc_reg_t weight_reg = COSWEIGHTSr; 2602 2603 *mode = *weight = 0; 2604 2605 BCM_IF_ERROR_RETURN 2606 (_bcm_tr2_cosq_resolve_mod_port(unit, gport, &modid, 2607 &local_port, &trunk_id)); 2608 if (!_tr2_num_port_cosq[unit]) { 2609 return BCM_E_INIT; 2610 } 2611 if (BCM_GPORT_IS_SCHEDULER(gport)) { 2612 if (_tr2_num_port_cosq[unit][local_port] == 0) { 2613 return BCM_E_NOT_FOUND; 2614 } else if (cosq >= _tr2_num_port_cosq[unit][local_port]) { 2615 return BCM_E_PARAM; 2616 } else if (cosq < 0) { 2617 cosq = 0; 2618 } 2619 config_reg = S1V_CONFIGr; 2620 weight_reg = S1V_COSWEIGHTSr; 2621 } else if (cosq == TR2_SCHEDULER_COSQ) { 2622 if (!SOC_PBMP_MEMBER(_tr2_cosq_24q_ports[unit], local_port)) { 2623 return BCM_E_PORT; 2624 } 2625 /* Weight for output of S1 scheduler is configured using offset 8 2626 * of COSWEIGHTS register. 2627 */ 2628 cosq = 8; 2629 } else { 2630 if (cosq >= _tr2_num_cosq[unit]) { 2631 return BCM_E_PARAM; 2632 } else if (cosq < 0) { 2633 cosq = 0; 2634 } 2635 } 2636 BCM_IF_ERROR_RETURN 2637 (_bcm_tr2_cosq_port_sched_get(unit, config_reg, weight_reg, 2638 local_port, cosq, 1, 2639 weight, mode)); 2640 return BCM_E_NONE; 2641 } 2642 2643 /* 2644 * Function: 2645 * bcm_cosq_gport_discard_set 2646 * Purpose: 2647 * 2648 * Parameters: 2649 * unit - (IN) Unit number. 2650 * port - (IN) GPORT ID. 2651 * cosq - (IN) COS queue to configure 2652 * discard - (IN) Discard settings 2653 * Returns: 2654 * BCM_E_XXX 2655 */ 2656 int 2657 bcm_tr2_cosq_gport_discard_set(int unit, bcm_gport_t port, 2658 bcm_cos_queue_t cosq, 2659 bcm_cosq_gport_discard_t *discard) 2660 { 2661 bcm_module_t modid; 2662 bcm_port_t local_port; 2663 bcm_trunk_t trunk_id; 2664 uint32 min_thresh, max_thresh; 2665 int cell_size, cell_field_max; 2666 2667 if ((discard == NULL) || 2668 (discard->gain < 0) || (discard->gain > 15) || 2669 (discard->drop_probability < 0) || (discard->drop_probability > 100)) { 2670 return BCM_E_PARAM; 2671 } 2672 2673 cell_size = _BCM_TR2_COSQ_CELLSIZE; 2674 cell_field_max = TR2_CELL_FIELD_MAX; 2675 2676 min_thresh = discard->min_thresh; 2677 max_thresh = discard->max_thresh; 2678 if (discard->flags & BCM_COSQ_DISCARD_BYTES) { 2679 /* Convert bytes to cells */ 2680 min_thresh += (cell_size - 1); 2681 min_thresh /= cell_size; 2682 2683 max_thresh += (cell_size - 1); 2684 max_thresh /= cell_size; 2685 2686 if ((min_thresh > cell_field_max) || 2687 (max_thresh > cell_field_max)) { 2688 return BCM_E_PARAM; 2689 } 2690 } else { /* BCM_COSQ_DISCARD_PACKETS */ 2691 if ((min_thresh > TR2_PACKET_FIELD_MAX) || 2692 (max_thresh > TR2_PACKET_FIELD_MAX)) { 2693 return BCM_E_PARAM; 2694 } 2695 } 2696 2697 if (port != BCM_GPORT_INVALID) { 2698 BCM_IF_ERROR_RETURN 2699 (_bcm_tr2_cosq_resolve_mod_port(unit, port, &modid, 2700 &local_port, &trunk_id)); 2701 if (cosq < 0) { 2702 /* per-port discard settings */ 2703 if (discard->flags & BCM_COSQ_DISCARD_BYTES) { 2704 BCM_IF_ERROR_RETURN 2705 (_bcm_tr2_cosq_discard_set(unit, local_port, 2706 discard->flags, 0, 2707 PORT_WREDCONFIG_CELLr, 2708 PORT_WREDPARAM_CELLr, 2709 PORT_WREDPARAM_YELLOW_CELLr, 2710 PORT_WREDPARAM_RED_CELLr, 2711 PORT_WREDPARAM_NONTCP_CELLr, 2712 min_thresh, max_thresh, 2713 discard->drop_probability, 2714 discard->gain)); 2715 BCM_IF_ERROR_RETURN 2716 (_bcm_tr2_cosq_discard_cap_enable_set(unit, local_port, 0, 2717 PORT_WREDCONFIG_CELLr, 2718 discard->flags)); 2719 2720 } else { /* BCM_COSQ_DISCARD_PACKETS */ 2721 BCM_IF_ERROR_RETURN 2722 (_bcm_tr2_cosq_discard_set(unit, local_port, 2723 discard->flags, 0, 2724 PORT_WREDCONFIG_PACKETr, 2725 PORT_WREDPARAM_PACKETr, 2726 PORT_WREDPARAM_YELLOW_PACKETr, 2727 PORT_WREDPARAM_RED_PACKETr, 2728 PORT_WREDPARAM_NONTCP_PACKETr, 2729 min_thresh, max_thresh, 2730 discard->drop_probability, 2731 discard->gain)); 2732 BCM_IF_ERROR_RETURN 2733 (_bcm_tr2_cosq_discard_cap_enable_set(unit, local_port, 0, 2734 PORT_WREDCONFIG_PACKETr, 2735 discard->flags)); 2736 } 2737 } else { 2738 /* per-port/per-cos discard settings */ 2739 if (BCM_GPORT_IS_SCHEDULER(port)) { 2740 if (_tr2_num_port_cosq[unit][local_port] == 0) { 2741 return BCM_E_NOT_FOUND; 2742 } else if (cosq >= _tr2_num_port_cosq[unit][local_port]) { 2743 return BCM_E_PARAM; 2744 } else { 2745 cosq = cosq + 8; 2746 } 2747 } else if (cosq >= _tr2_num_cosq[unit]) { 2748 return BCM_E_PARAM; 2749 } 2750 2751 if (discard->flags & BCM_COSQ_DISCARD_BYTES) { 2752 BCM_IF_ERROR_RETURN 2753 (_bcm_tr2_cosq_discard_set(unit, local_port, 2754 discard->flags, cosq, 2755 WREDCONFIG_CELLr, 2756 WREDPARAM_CELLr, 2757 WREDPARAM_YELLOW_CELLr, 2758 WREDPARAM_RED_CELLr, 2759 WREDPARAM_NONTCP_CELLr, 2760 min_thresh, max_thresh, 2761 discard->drop_probability, 2762 discard->gain)); 2763 BCM_IF_ERROR_RETURN 2764 (_bcm_tr2_cosq_discard_cap_enable_set(unit, local_port, cosq, 2765 WREDCONFIG_CELLr, 2766 discard->flags)); 2767 } else { /* BCM_COSQ_DISCARD_PACKETS */ 2768 BCM_IF_ERROR_RETURN 2769 (_bcm_tr2_cosq_discard_set(unit, local_port, 2770 discard->flags, cosq, 2771 WREDCONFIG_PACKETr, 2772 WREDPARAM_PACKETr, 2773 WREDPARAM_YELLOW_PACKETr, 2774 WREDPARAM_RED_PACKETr, 2775 WREDPARAM_NONTCP_PACKETr, 2776 min_thresh, max_thresh, 2777 discard->drop_probability, 2778 discard->gain)); 2779 BCM_IF_ERROR_RETURN 2780 (_bcm_tr2_cosq_discard_cap_enable_set(unit, local_port, cosq, 2781 WREDCONFIG_PACKETr, 2782 discard->flags)); 2783 } 2784 } 2785 } else { 2786 /* chip-wide discard settings */ 2787 if (discard->flags & BCM_COSQ_DISCARD_BYTES) { 2788 BCM_IF_ERROR_RETURN 2789 (_bcm_tr2_cosq_discard_set(unit, REG_PORT_ANY, discard->flags, 2790 0, GLOBAL_WREDCONFIG_CELLr, 2791 GLOBAL_WREDPARAM_CELLr, 2792 GLOBAL_WREDPARAM_YELLOW_CELLr, 2793 GLOBAL_WREDPARAM_RED_CELLr, 2794 GLOBAL_WREDPARAM_NONTCP_CELLr, 2795 min_thresh, max_thresh, 2796 discard->drop_probability, 2797 discard->gain)); 2798 BCM_IF_ERROR_RETURN 2799 (_bcm_tr2_cosq_discard_cap_enable_set(unit, REG_PORT_ANY, 0, 2800 GLOBAL_WREDCONFIG_CELLr, 2801 discard->flags)); 2802 } else { /* BCM_COSQ_DISCARD_PACKETS */ 2803 BCM_IF_ERROR_RETURN 2804 (_bcm_tr2_cosq_discard_set(unit, REG_PORT_ANY, discard->flags, 2805 0, GLOBAL_WREDCONFIG_PACKETr, 2806 GLOBAL_WREDPARAM_PACKETr, 2807 GLOBAL_WREDPARAM_YELLOW_PACKETr, 2808 GLOBAL_WREDPARAM_RED_PACKETr, 2809 GLOBAL_WREDPARAM_NONTCP_PACKETr, 2810 min_thresh, max_thresh, 2811 discard->drop_probability, 2812 discard->gain)); 2813 BCM_IF_ERROR_RETURN 2814 (_bcm_tr2_cosq_discard_cap_enable_set(unit, REG_PORT_ANY, 0, 2815 GLOBAL_WREDCONFIG_PACKETr, 2816 discard->flags)); 2817 } 2818 } 2819 return BCM_E_NONE; 2820 } 2821 2822 /* 2823 * Function: 2824 * bcm_cosq_gport_discard_get 2825 * Purpose: 2826 * 2827 * Parameters: 2828 * unit - (IN) Unit number. 2829 * port - (IN) GPORT ID. 2830 * cosq - (IN) COS queue to get 2831 * discard - (IN/OUT) Discard settings 2832 * Returns: 2833 * BCM_E_XXX 2834 */ 2835 int 2836 bcm_tr2_cosq_gport_discard_get(int unit, bcm_gport_t port, bcm_cos_queue_t cosq, 2837 bcm_cosq_gport_discard_t *discard) 2838 { 2839 bcm_module_t modid; 2840 bcm_port_t local_port; 2841 bcm_trunk_t trunk_id; 2842 uint32 min_thresh, max_thresh; 2843 2844 if (discard == NULL) { 2845 return BCM_E_PARAM; 2846 } 2847 2848 if (port != BCM_GPORT_INVALID) { 2849 BCM_IF_ERROR_RETURN 2850 (_bcm_tr2_cosq_resolve_mod_port(unit, port, &modid, 2851 &local_port, &trunk_id)); 2852 if (cosq < 0) { 2853 /* per-port discard settings */ 2854 if (discard->flags & BCM_COSQ_DISCARD_BYTES) { 2855 BCM_IF_ERROR_RETURN 2856 (_bcm_tr2_cosq_discard_get(unit, local_port, 2857 discard->flags, 0, 2858 PORT_WREDCONFIG_CELLr, 2859 PORT_WREDPARAM_CELLr, 2860 PORT_WREDPARAM_YELLOW_CELLr, 2861 PORT_WREDPARAM_RED_CELLr, 2862 PORT_WREDPARAM_NONTCP_CELLr, 2863 &min_thresh, &max_thresh, 2864 &discard->drop_probability, 2865 &discard->gain)); 2866 BCM_IF_ERROR_RETURN 2867 (_bcm_tr2_cosq_discard_cap_enable_get(unit, local_port, 0, 2868 PORT_WREDCONFIG_CELLr, 2869 &discard->flags)); 2870 } else { /* BCM_COSQ_DISCARD_PACKETS */ 2871 BCM_IF_ERROR_RETURN 2872 (_bcm_tr2_cosq_discard_get(unit, local_port, 2873 discard->flags, 0, 2874 PORT_WREDCONFIG_PACKETr, 2875 PORT_WREDPARAM_PACKETr, 2876 PORT_WREDPARAM_YELLOW_PACKETr, 2877 PORT_WREDPARAM_RED_PACKETr, 2878 PORT_WREDPARAM_NONTCP_PACKETr, 2879 &min_thresh, &max_thresh, 2880 &discard->drop_probability, 2881 &discard->gain)); 2882 BCM_IF_ERROR_RETURN 2883 (_bcm_tr2_cosq_discard_cap_enable_get(unit, local_port, 0, 2884 PORT_WREDCONFIG_PACKETr, 2885 &discard->flags)); 2886 } 2887 } else { 2888 /* per-port/per-cos discard settings */ 2889 if (BCM_GPORT_IS_SCHEDULER(port)) { 2890 if (_tr2_num_port_cosq[unit][local_port] == 0) { 2891 return BCM_E_NOT_FOUND; 2892 } else if (cosq >= _tr2_num_port_cosq[unit][local_port]) { 2893 return BCM_E_PARAM; 2894 } else { 2895 cosq = cosq + 8; 2896 } 2897 } else if (cosq >= _tr2_num_cosq[unit]) { 2898 return BCM_E_PARAM; 2899 } 2900 2901 if (discard->flags & BCM_COSQ_DISCARD_BYTES) { 2902 BCM_IF_ERROR_RETURN 2903 (_bcm_tr2_cosq_discard_get(unit, local_port, 2904 discard->flags, cosq, 2905 WREDCONFIG_CELLr, 2906 WREDPARAM_CELLr, 2907 WREDPARAM_YELLOW_CELLr, 2908 WREDPARAM_RED_CELLr, 2909 WREDPARAM_NONTCP_CELLr, 2910 &min_thresh, &max_thresh, 2911 &discard->drop_probability, 2912 &discard->gain)); 2913 BCM_IF_ERROR_RETURN 2914 (_bcm_tr2_cosq_discard_cap_enable_get(unit, local_port, cosq, 2915 WREDCONFIG_CELLr, 2916 &discard->flags)); 2917 } else { /* BCM_COSQ_DISCARD_PACKETS */ 2918 BCM_IF_ERROR_RETURN 2919 (_bcm_tr2_cosq_discard_get(unit, local_port, 2920 discard->flags, cosq, 2921 WREDCONFIG_PACKETr, 2922 WREDPARAM_PACKETr, 2923 WREDPARAM_YELLOW_PACKETr, 2924 WREDPARAM_RED_PACKETr, 2925 WREDPARAM_NONTCP_PACKETr, 2926 &min_thresh, &max_thresh, 2927 &discard->drop_probability, 2928 &discard->gain)); 2929 BCM_IF_ERROR_RETURN 2930 (_bcm_tr2_cosq_discard_cap_enable_get(unit, local_port, cosq, 2931 WREDCONFIG_PACKETr, 2932 &discard->flags)); 2933 } 2934 } 2935 } else { 2936 /* chip-wide discard settings */ 2937 if (discard->flags & BCM_COSQ_DISCARD_BYTES) { 2938 BCM_IF_ERROR_RETURN 2939 (_bcm_tr2_cosq_discard_get(unit, REG_PORT_ANY, discard->flags, 2940 0, GLOBAL_WREDCONFIG_CELLr, 2941 GLOBAL_WREDPARAM_CELLr, 2942 GLOBAL_WREDPARAM_YELLOW_CELLr, 2943 GLOBAL_WREDPARAM_RED_CELLr, 2944 GLOBAL_WREDPARAM_NONTCP_CELLr, 2945 &min_thresh, &max_thresh, 2946 &discard->drop_probability, 2947 &discard->gain)); 2948 BCM_IF_ERROR_RETURN 2949 (_bcm_tr2_cosq_discard_cap_enable_get(unit, REG_PORT_ANY, 0, 2950 GLOBAL_WREDCONFIG_CELLr, 2951 &discard->flags)); 2952 } else { /* BCM_COSQ_DISCARD_PACKETS */ 2953 BCM_IF_ERROR_RETURN 2954 (_bcm_tr2_cosq_discard_get(unit, REG_PORT_ANY, discard->flags, 2955 0, GLOBAL_WREDCONFIG_PACKETr, 2956 GLOBAL_WREDPARAM_PACKETr, 2957 GLOBAL_WREDPARAM_YELLOW_PACKETr, 2958 GLOBAL_WREDPARAM_RED_PACKETr, 2959 GLOBAL_WREDPARAM_NONTCP_PACKETr, 2960 &min_thresh, &max_thresh, 2961 &discard->drop_probability, 2962 &discard->gain)); 2963 BCM_IF_ERROR_RETURN 2964 (_bcm_tr2_cosq_discard_cap_enable_get(unit, REG_PORT_ANY, 0, 2965 GLOBAL_WREDCONFIG_PACKETr, 2966 &discard->flags)); 2967 } 2968 } 2969 2970 if (discard->flags & BCM_COSQ_DISCARD_BYTES) { 2971 /* Convert cells to bytes */ 2972 min_thresh *= _BCM_TR2_COSQ_CELLSIZE; 2973 max_thresh *= _BCM_TR2_COSQ_CELLSIZE; 2974 } 2975 discard->min_thresh = min_thresh; 2976 discard->max_thresh = max_thresh; 2977 2978 return BCM_E_NONE; 2979 } 2980 2981 /* 2982 * Function: 2983 * bcm_cosq_gport_attach 2984 * Purpose: 2985 * 2986 * Parameters: 2987 * unit - (IN) Unit number. 2988 * sched_port - (IN) Scheduler GPORT ID. 2989 * input_port - (IN) GPORT to attach to. 2990 * cosq - (IN) COS queue to attach to. 2991 * Returns: 2992 * BCM_E_XXX 2993 */ 2994 int 2995 bcm_tr2_cosq_gport_attach(int unit, bcm_gport_t sched_gport, 2996 bcm_gport_t input_gport, bcm_cos_queue_t cosq) 2997 { 2998 bcm_module_t sched_modid, input_modid; 2999 bcm_port_t sched_port, input_port; 3000 bcm_trunk_t trunk_id; 3001 3002 if (!BCM_GPORT_IS_SCHEDULER(sched_gport)) { 3003 return BCM_E_PARAM; 3004 } else if (!_tr2_num_port_cosq[unit]) { 3005 return BCM_E_INIT; 3006 } else if (cosq < 0) { 3007 cosq = TR2_SCHEDULER_COSQ; 3008 } else if (cosq != TR2_SCHEDULER_COSQ) { 3009 return BCM_E_PARAM; 3010 } 3011 3012 BCM_IF_ERROR_RETURN 3013 (_bcm_tr2_cosq_resolve_mod_port(unit, sched_gport, &sched_modid, 3014 &sched_port, &trunk_id)); 3015 3016 BCM_IF_ERROR_RETURN 3017 (_bcm_tr2_cosq_resolve_mod_port(unit, input_gport, &input_modid, 3018 &input_port, &trunk_id)); 3019 3020 if (_tr2_num_port_cosq[unit][sched_port] == 0) { 3021 /* GPORT has not been added. */ 3022 return BCM_E_NOT_FOUND; 3023 } else if ((sched_modid != input_modid) || (sched_port != input_port)) { 3024 /* Be sure the GPORT matches to the physical port */ 3025 return BCM_E_PARAM; 3026 } 3027 3028 BCM_IF_ERROR_RETURN 3029 (soc_reg_field32_modify(unit, ING_COS_MODEr, input_port, 3030 SELECTf, 0x3)); /* VLAN_COS */ 3031 BCM_IF_ERROR_RETURN 3032 (soc_reg_field32_modify(unit, COS_MODEr, input_port, 3033 SELECTf, 0x3)); /* VLAN_COS */ 3034 return BCM_E_NONE; 3035 } 3036 3037 /* 3038 * Function: 3039 * bcm_cosq_gport_detach 3040 * Purpose: 3041 * 3042 * Parameters: 3043 * unit - (IN) Unit number. 3044 * sched_port - (IN) Scheduler GPORT ID. 3045 * input_port - (IN) GPORT to detach from. 3046 * cosq - (IN) COS queue to detach from. 3047 * Returns: 3048 * BCM_E_XXX 3049 * Notes: 3050 */ 3051 int 3052 bcm_tr2_cosq_gport_detach(int unit, bcm_gport_t sched_gport, 3053 bcm_gport_t input_gport, bcm_cos_queue_t cosq) 3054 { 3055 bcm_module_t sched_modid, input_modid; 3056 bcm_port_t sched_port, input_port; 3057 bcm_trunk_t trunk_id; 3058 3059 if (!BCM_GPORT_IS_SCHEDULER(sched_gport)) { 3060 return BCM_E_PORT; 3061 } else if (!_tr2_num_port_cosq[unit]) { 3062 return BCM_E_INIT; 3063 } else if ((cosq > 0) && (cosq != TR2_SCHEDULER_COSQ)) { 3064 return BCM_E_NOT_FOUND; 3065 } 3066 3067 BCM_IF_ERROR_RETURN 3068 (_bcm_tr2_cosq_resolve_mod_port(unit, sched_gport, &sched_modid, 3069 &sched_port, &trunk_id)); 3070 BCM_IF_ERROR_RETURN 3071 (_bcm_tr2_cosq_resolve_mod_port(unit, input_gport, &input_modid, 3072 &input_port, &trunk_id)); 3073 if (_tr2_num_port_cosq[unit][sched_port] == 0) { 3074 /* GPORT has not been added. */ 3075 return BCM_E_NOT_FOUND; 3076 } else if ((sched_modid != input_modid) || (sched_port != input_port)) { 3077 /* Be sure the GPORT matches to the physical port */ 3078 return BCM_E_PORT; 3079 } 3080 3081 BCM_IF_ERROR_RETURN 3082 (soc_reg_field32_modify(unit, COS_MODEr, input_port, SELECTf, 0x0)); 3083 BCM_IF_ERROR_RETURN 3084 (soc_reg_field32_modify(unit, ING_COS_MODEr, input_port, SELECTf, 0x0)); 3085 return BCM_E_NONE; 3086 } 3087 3088 /* 3089 * Function: 3090 * bcm_cosq_gport_attach_get 3091 * Purpose: 3092 * 3093 * Parameters: 3094 * unit - (IN) Unit number. 3095 * sched_port - (IN) Scheduler GPORT ID. 3096 * input_port - (OUT) GPORT attached to. 3097 * cosq - (OUT) COS queue attached to. 3098 * Returns: 3099 * BCM_E_XXX 3100 * Notes: 3101 */ 3102 int 3103 bcm_tr2_cosq_gport_attach_get(int unit, bcm_gport_t sched_gport, 3104 bcm_gport_t *input_gport, bcm_cos_queue_t *cosq) 3105 { 3106 bcm_module_t sched_modid, input_modid; 3107 bcm_port_t sched_port, input_port; 3108 bcm_trunk_t trunk_id; 3109 uint32 val; 3110 3111 if (!BCM_GPORT_IS_SCHEDULER(sched_gport) || 3112 !cosq || !input_gport) { 3113 return BCM_E_PARAM; 3114 } else if (!_tr2_num_port_cosq[unit]) { 3115 return BCM_E_INIT; 3116 } 3117 3118 BCM_IF_ERROR_RETURN 3119 (_bcm_tr2_cosq_resolve_mod_port(unit, sched_gport, &sched_modid, 3120 &sched_port, &trunk_id)); 3121 if (_tr2_num_port_cosq[unit][sched_port] == 0) { 3122 /* GPORT has not been added. */ 3123 return BCM_E_NOT_FOUND; 3124 } 3125 3126 BCM_IF_ERROR_RETURN(READ_COS_MODEr(unit, sched_port, &val)); 3127 if (soc_reg_field_get(unit, COS_MODEr, val, SELECTf) == 3) { 3128 /* GPORT has been attached */ 3129 *cosq = TR2_SCHEDULER_COSQ; 3130 3131 BCM_IF_ERROR_RETURN 3132 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET, 3133 sched_modid, sched_port, 3134 &input_modid, &input_port)); 3135 BCM_GPORT_MODPORT_SET(*input_gport, input_modid, input_port); 3136 } else { 3137 /* GPORT has not been attached */ 3138 return BCM_E_NOT_FOUND; 3139 } 3140 return BCM_E_NONE; 3141 } 3142 3143 #ifndef BCM_SW_STATE_DUMP_DISABLE 3144 /* 3145 * Function: 3146 * bcm_tr2_cosq_sw_dump 3147 * Purpose: 3148 * Displays COS Queue information maintained by software. 3149 * Parameters: 3150 * unit - Device unit number 3151 * Returns: 3152 * None 3153 */ 3154 void 3155 bcm_tr2_cosq_sw_dump(int unit) 3156 { 3157 int i; 3158 3159 LOG_CLI((BSL_META_U(unit, 3160 "\nSW Information COSQ - Unit %d\n"), unit)); 3161 3162 /* Number COSQ */ 3163 LOG_CLI((BSL_META_U(unit, 3164 " Number: %d\n"), _tr2_num_cosq[unit])); 3165 3166 /* Number of COSQs per port */ 3167 LOG_CLI((BSL_META_U(unit, 3168 " Number COSQ per port:\n"))); 3169 if (_tr2_num_port_cosq[unit]) { 3170 for (i = 0; i < TR2_PORT_COUNT; i++) { 3171 LOG_CLI((BSL_META_U(unit, 3172 " Port %2d: %d\n"), i, 3173 _tr2_num_port_cosq[unit][i])); 3174 } 3175 } 3176 3177 /* COSQ Map profile */ 3178 /* Display those entries with reference count > 0 */ 3179 LOG_CLI((BSL_META_U(unit, 3180 " COSQ Map Profile:\n"))); 3181 if (_tr2_cos_map_profile[unit] != NULL) { 3182 int num_entries; 3183 int ref_count; 3184 int entries_per_set; 3185 uint32 index; 3186 uint32 cosq, hg_cosq; 3187 port_cos_map_entry_t *entry_p; 3188 3189 num_entries = soc_mem_index_count 3190 (unit, _tr2_cos_map_profile[unit]->tables[0].mem); 3191 LOG_CLI((BSL_META_U(unit, 3192 " Number of entries: %d\n"), num_entries)); 3193 LOG_CLI((BSL_META_U(unit, 3194 " Index RefCount EntriesPerSet - " 3195 "COS HG_COS\n"))); 3196 3197 for (index = 0; index < num_entries; 3198 index += TR2_COS_MAP_ENTRIES_PER_SET) { 3199 if (SOC_FAILURE 3200 (soc_profile_mem_ref_count_get(unit, 3201 _tr2_cos_map_profile[unit], 3202 index, &ref_count))) { 3203 break; 3204 } 3205 3206 if (ref_count <= 0) { 3207 continue; 3208 } 3209 3210 for (i = 0; i < TR2_COS_MAP_ENTRIES_PER_SET; i++) { 3211 entries_per_set = 3212 _tr2_cos_map_profile[unit]->tables[0].entries[index+i].entries_per_set; 3213 LOG_CLI((BSL_META_U(unit, 3214 " %5d %8d %13d "), 3215 index + i, ref_count, entries_per_set)); 3216 3217 entry_p = SOC_PROFILE_MEM_ENTRY(unit, 3218 _tr2_cos_map_profile[unit], 3219 port_cos_map_entry_t *, 3220 index + i); 3221 cosq = soc_mem_field32_get(unit, 3222 PORT_COS_MAPm, 3223 entry_p, 3224 COSf); 3225 LOG_CLI((BSL_META_U(unit, 3226 "%2d "), cosq)); 3227 if (soc_mem_field_valid(unit, PORT_COS_MAPm, HG_COSf)) { 3228 hg_cosq = soc_mem_field32_get(unit, PORT_COS_MAPm, 3229 entry_p, 3230 HG_COSf); 3231 LOG_CLI((BSL_META_U(unit, 3232 " %2d"), hg_cosq)); 3233 } 3234 LOG_CLI((BSL_META_U(unit, 3235 "\n"))); 3236 } 3237 } 3238 } 3239 3240 /* Egress COSQ Map profile */ 3241 /* Display those entries with reference count > 0 */ 3242 LOG_CLI((BSL_META_U(unit, 3243 " Egress COSQ Map Profile:\n"))); 3244 if (_tr2_cos_egr_map_profile[unit] != NULL) { 3245 int num_entries; 3246 int ref_count; 3247 int entries_per_set; 3248 uint32 index; 3249 uint32 cosq; 3250 egr_cos_map_entry_t *entry_p; 3251 3252 num_entries = soc_mem_index_count 3253 (unit, _tr2_cos_egr_map_profile[unit]->tables[0].mem); 3254 LOG_CLI((BSL_META_U(unit, 3255 " Number of entries: %d\n"), num_entries)); 3256 LOG_CLI((BSL_META_U(unit, 3257 " Index RefCount EntriesPerSet - " 3258 "Entry: REDIRECT_COS\n"))); 3259 3260 for (index = 0; index < num_entries; 3261 index += TR2_COS_MAP_ENTRIES_PER_SET) { 3262 if (SOC_FAILURE 3263 (soc_profile_mem_ref_count_get(unit, 3264 _tr2_cos_egr_map_profile[unit], 3265 index, &ref_count))) { 3266 break; 3267 } 3268 3269 if (ref_count <= 0) { 3270 continue; 3271 } 3272 3273 for (i = 0; i < TR2_COS_MAP_ENTRIES_PER_SET; i++) { 3274 entries_per_set = 3275 _tr2_cos_egr_map_profile[unit]->tables[0].entries[index+i].entries_per_set; 3276 LOG_CLI((BSL_META_U(unit, 3277 " %5d %8d %13d "), 3278 index + i, ref_count, entries_per_set)); 3279 3280 entry_p = SOC_PROFILE_MEM_ENTRY(unit, 3281 _tr2_cos_egr_map_profile[unit], 3282 egr_cos_map_entry_t *, 3283 index + i); 3284 cosq = soc_mem_field32_get(unit, 3285 EGR_COS_MAPm, 3286 entry_p, 3287 REDIRECT_COSf); 3288 LOG_CLI((BSL_META_U(unit, 3289 " %3d "), cosq)); 3290 3291 LOG_CLI((BSL_META_U(unit, 3292 "\n"))); 3293 } 3294 } 3295 } 3296 3297 return; 3298 } 3299 #endif /* BCM_SW_STATE_DUMP_DISABLE */ 3300 3301 #else /* BCM_TRIUMPH2_SUPPORT */ 3302 int _tr2_cosq_not_empty; 3303 #endif /* BCM_TRIUMPH2_SUPPORT */ 3304