cosq.c (212175B)
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 8 #include <soc/defs.h> 9 10 #include <assert.h> 11 12 #include <sal/core/libc.h> 13 #if defined(BCM_GREYHOUND2_SUPPORT) 14 #include <shared/util.h> 15 #include <soc/mem.h> 16 #include <soc/cm.h> 17 #include <soc/drv.h> 18 #include <soc/scache.h> 19 #include <soc/register.h> 20 #include <soc/memory.h> 21 #include <soc/greyhound2.h> 22 #include <bcm_int/esw/port.h> 23 #include <bcm_int/esw/cosq.h> 24 #include <bcm_int/esw/ecn.h> 25 #include <bcm_int/esw/tas.h> 26 #include <bcm_int/esw/firebolt.h> 27 #include <bcm_int/esw/greyhound2.h> 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 GH2_DRR_KBYTES (1) 35 #define GH2_DRR_WEIGHT_MAX 0x7f 36 #define GH2_WRR_WEIGHT_MAX 0x7f 37 38 #define GH2_MTU_QUANTA_ID_COUNT 4 39 #define GH2_COS_WEIGHT_MAX 0x7f 40 41 static int MTU_GH2_Quanta[GH2_MTU_QUANTA_ID_COUNT] = { 42 2 * GH2_DRR_KBYTES, /* Quanta of 2048 bytes */ 43 4 * GH2_DRR_KBYTES, /* Quanta of 4096 bytes */ 44 8 * GH2_DRR_KBYTES, /* Quanta of 8192 bytes */ 45 16 * GH2_DRR_KBYTES /* Quanta of 16384 bytes */ 46 }; 47 48 49 /* COS Map profile entries per set */ 50 #define GH2_COS_MAP_ENTRIES_PER_SET 16 51 52 #define GH2_BURST_GRANULARITY 64 /* 64bytes */ 53 #define GH2_BURST_GRANULARITY_DEFAULT GH2_BURST_GRANULARITY 54 #define GH2_BURST_GRANULARITY_128B 128 /* 128 bytes */ 55 #define GH2_BW_FIELD_MAX 0x3FFFF 56 57 /* Cache of COS_MAP Profile Table */ 58 STATIC soc_profile_mem_t *gh2_cos_map_profile[BCM_MAX_NUM_UNITS] = {NULL}; 59 60 /* WRED definition */ 61 /* WRED update interval unit : us */ 62 STATIC int gh2_wred_update_interval[BCM_MAX_NUM_UNITS]; 63 STATIC soc_profile_mem_t *gh2_wred_profile[BCM_MAX_NUM_UNITS]; 64 65 #define GH2_CELL_FIELD_MAX 0x7fff 66 67 /* MMU cell size in bytes */ 68 #define GH2_BYTES_PER_CELL 144 /* bytes */ 69 #define GH2_BYTES_TO_CELLS(_byte_) \ 70 (((_byte_) + GH2_BYTES_PER_CELL - 1) / GH2_BYTES_PER_CELL) 71 72 #define GH2_PORT_LVL_SCHEDULER_PER_PORT 1 73 #define GH2_QGROUP_LVL_SCHEDULER_PER_PORT 1 74 #define GH2_QLAYER_LVL_SCHEDULER_PER_PORT 8 75 /* 8 ports support 2 level scheduling */ 76 #define GH2_NUM_TWO_LEVEL_SCHEDULER_PORT \ 77 (SOC_GH2_64Q_MMU_PORT_IDX_MAX - SOC_GH2_64Q_MMU_PORT_IDX_MIN + 1) 78 /* 10 Scheduler node per port */ 79 #define GH2_NUM_SCHEDULERS_PER_PORT \ 80 (GH2_PORT_LVL_SCHEDULER_PER_PORT + \ 81 GH2_QGROUP_LVL_SCHEDULER_PER_PORT + \ 82 GH2_QLAYER_LVL_SCHEDULER_PER_PORT) 83 84 /* 85 * The first 8 Scheduler nodes are reserved for PORT_LEVEL scheduler of 86 * the 8 MMU port . 87 * The other 72 Scheduler nodes are for QGROUP and QLAYER schedulers 88 * of the MMU ports. 89 */ 90 /* 8/80 Schedulres node for PORT_LEVEL */ 91 #define GH2_NUM_PORT_SCHEDULERS 8 92 /* 8/80 Schedulres node for QGROUP */ 93 #define GH2_NUM_QGROUP_SCHEDULERS \ 94 (GH2_QGROUP_LVL_SCHEDULER_PER_PORT * \ 95 GH2_NUM_TWO_LEVEL_SCHEDULER_PORT) 96 /* 64/80 Schedulres node for QLAYER */ 97 #define GH2_NUM_QLAYER_SCHEDULERS \ 98 (GH2_QLAYER_LVL_SCHEDULER_PER_PORT * \ 99 GH2_NUM_TWO_LEVEL_SCHEDULER_PORT) 100 /* 80 Scheduler node total */ 101 #define GH2_NUM_TOTAL_SCHEDULERS (GH2_NUM_PORT_SCHEDULERS + \ 102 GH2_NUM_QGROUP_SCHEDULERS + \ 103 GH2_NUM_QLAYER_SCHEDULERS) 104 105 /* Queue node total */ 106 #define GH2_NUM_TOTAL_QUEUES (GH2_NUM_TWO_LEVEL_SCHEDULER_PORT * \ 107 SOC_GH2_QLAYER_COSQ_PER_PORT_NUM) 108 109 110 typedef enum { 111 GH2_COSQ_LEVEL_PORT = 0, /* port level */ 112 GH2_COSQ_LEVEL_QGROUP, /* QGroup level (L0) */ 113 GH2_COSQ_LEVEL_QLAYER, /* QLayer level (L1) */ 114 GH2_COSQ_LEVEL_QUEUE /* Queue level (L2)*/ 115 } gh2_cosq_level_type_t; 116 117 typedef struct gh2_cosq_node_s { 118 int in_use; 119 int node_id; /* internal node id */ 120 bcm_gport_t node_gport; /* node gport id */ 121 gh2_cosq_level_type_t node_level; /* QGROUP, QLAYER, QUEUE */ 122 int max_num_child; 123 124 /* parameters for node_level = QGROUP, QLAYER, QUEUE */ 125 bcm_gport_t parent_gport; /* parent node's gport id */ 126 127 /* parameters for node_level = PORT, QGROUP, QLAYER */ 128 /* number of child, value 0~8 */ 129 int num_child; 130 /* all childrens' gport id */ 131 bcm_gport_t child_gport[GH2_QLAYER_LVL_SCHEDULER_PER_PORT]; 132 133 /* parameters for node_level = QLAYER, QUEUE */ 134 /* the X-st child of parent node, valid X is 0-7 */ 135 int child_idx; 136 137 /* QLAYER's queue range's min, value=child_idx * 8 */ 138 int qlayer_cosq_min; 139 /* QLAYER's queue range's max, value=(child_idx+1)*8-1 */ 140 int qlayer_cosq_max; 141 } gh2_cosq_node_t; 142 143 typedef struct gh2_mmu_info_s { 144 /* scheduler nodes */ 145 gh2_cosq_node_t sched_node[GH2_NUM_TOTAL_SCHEDULERS]; 146 /* queue nodes */ 147 gh2_cosq_node_t queue_node[GH2_NUM_TOTAL_QUEUES]; 148 } gh2_mmu_info_t; 149 150 /* MMU info of scheduler and queue nodes */ 151 STATIC gh2_mmu_info_t *gh2_mmu_info[BCM_MAX_NUM_UNITS]; 152 153 /* Number of COSQs configured for this device */ 154 STATIC int gh2_num_cosq[SOC_MAX_NUM_DEVICES]; 155 156 #ifdef BCM_WARM_BOOT_SUPPORT 157 158 #define BCM_WB_VERSION_1_0 SOC_SCACHE_VERSION(1, 0) 159 #define BCM_WB_DEFAULT_VERSION BCM_WB_VERSION_1_0 160 161 /* 162 * Function: 163 * bcmi_gh2_cosq_sync 164 * Purpose: 165 * Record COSQ module persistent info for Level 2 Warm Boot. 166 * Parameters: 167 * unit - Unit number. 168 * Returns: 169 * BCM_E_XXX 170 */ 171 int 172 bcmi_gh2_cosq_sync(int unit) 173 { 174 soc_scache_handle_t scache_handle; 175 uint8 *cosq_scache_ptr; 176 uint32 num_cosq; 177 gh2_mmu_info_t *mmu_info; 178 179 mmu_info = gh2_mmu_info[unit]; 180 181 if (!mmu_info) { 182 return BCM_E_INIT; 183 } 184 185 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 0); 186 BCM_IF_ERROR_RETURN 187 (_bcm_esw_scache_ptr_get(unit, scache_handle, FALSE, 188 0, &cosq_scache_ptr, 189 BCM_WB_DEFAULT_VERSION, NULL)); 190 /* Number COSQ */ 191 num_cosq = gh2_num_cosq[unit]; 192 sal_memcpy(cosq_scache_ptr, &num_cosq, sizeof(num_cosq)); 193 194 /* 2-level scheduling scheduler nodes */ 195 cosq_scache_ptr += sizeof(num_cosq); 196 sal_memcpy(cosq_scache_ptr, 197 gh2_mmu_info[unit], sizeof(gh2_mmu_info_t)); 198 return BCM_E_NONE; 199 } 200 201 /* 202 * Function: 203 * bcmi_gh2_cosq_reinit 204 * Purpose: 205 * Recover COSQ software state. 206 * Parameters: 207 * unit - Unit number. 208 * Returns: 209 * BCM_E_XXX 210 */ 211 STATIC int 212 bcmi_gh2_cosq_reinit(int unit) 213 { 214 int rv; 215 soc_scache_handle_t scache_handle; 216 uint8 *cosq_scache_ptr; 217 uint32 num_cosq; 218 int i, profile_index; 219 mmu_wred_config_entry_t qentry; 220 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 0); 221 rv = _bcm_esw_scache_ptr_get(unit, scache_handle, FALSE, 222 0, &cosq_scache_ptr, 223 BCM_WB_DEFAULT_VERSION, NULL); 224 225 if (rv == BCM_E_NOT_FOUND) { 226 cosq_scache_ptr = NULL; 227 } else if (BCM_FAILURE(rv)) { 228 return rv; 229 } 230 231 if (cosq_scache_ptr != NULL) { 232 /* Number COSQ */ 233 sal_memcpy(&num_cosq, cosq_scache_ptr, sizeof(num_cosq)); 234 gh2_num_cosq[unit] = num_cosq; 235 236 cosq_scache_ptr += sizeof(num_cosq); 237 238 /* 2-level scheduling scheduler nodes */ 239 if (gh2_mmu_info[unit] != NULL) { 240 sal_memcpy(gh2_mmu_info[unit], cosq_scache_ptr, 241 sizeof(gh2_mmu_info_t)); 242 } 243 } else { 244 gh2_num_cosq[unit] = _bcm_esw_cosq_config_property_get(unit); 245 } 246 247 if (soc_feature(unit, soc_feature_discard_ability)) { 248 for (i = soc_mem_index_min(unit, MMU_WRED_CONFIGm); 249 i <= soc_mem_index_max(unit, MMU_WRED_CONFIGm); i++) { 250 BCM_IF_ERROR_RETURN( 251 soc_mem_read(unit, MMU_WRED_CONFIGm, 252 MEM_BLOCK_ALL, i, &qentry)); 253 254 profile_index = soc_mem_field32_get(unit, MMU_WRED_CONFIGm, 255 &qentry, PROFILE_INDEXf); 256 257 BCM_IF_ERROR_RETURN 258 (soc_profile_mem_reference(unit, gh2_wred_profile[unit], 259 profile_index, 1)); 260 } 261 262 for (i = soc_mem_index_min(unit, MMU_WRED_CONFIG_QGROUPm); 263 i <= soc_mem_index_max(unit, MMU_WRED_CONFIG_QGROUPm); i++) { 264 BCM_IF_ERROR_RETURN( 265 soc_mem_read(unit, MMU_WRED_CONFIG_QGROUPm, 266 MEM_BLOCK_ALL, i, &qentry)); 267 268 profile_index = soc_mem_field32_get(unit, MMU_WRED_CONFIG_QGROUPm, 269 &qentry, PROFILE_INDEXf); 270 271 BCM_IF_ERROR_RETURN 272 (soc_profile_mem_reference(unit, gh2_wred_profile[unit], 273 profile_index, 1)); 274 } 275 } 276 277 return BCM_E_NONE; 278 } 279 280 #endif /* BCM_WARM_BOOT_SUPPORT */ 281 282 /* 283 * Function: 284 * bcmi_gh2_cosq_node_t_init 285 * Purpose: 286 * Initialize node information 287 * Parameters: 288 * node - (IN) node structure 289 * Returns: 290 * BCM_E_XXX 291 */ 292 STATIC void 293 bcmi_gh2_cosq_node_t_init(gh2_cosq_node_t *node) 294 { 295 int i; 296 297 node->in_use = FALSE; 298 node->node_id = -1; 299 node->node_gport = -1; 300 node->node_level = -1; 301 node->parent_gport = -1; 302 node->max_num_child = 0; 303 node->num_child = 0; 304 node->child_idx = -1; 305 node->qlayer_cosq_min = -1; 306 node->qlayer_cosq_max = -1; 307 for (i = 0; i < GH2_QLAYER_LVL_SCHEDULER_PER_PORT; i++) { 308 node->child_gport[i] = BCM_GPORT_INVALID; 309 } 310 } 311 312 /* 313 * Function: 314 * bcmi_gh2_cosq_node_get 315 * Purpose: 316 * Get internal information of scheduler type GPORT 317 * Parameters: 318 * unit - (IN) unit number 319 * gport - (IN) queue group/scheduler GPORT identifier 320 * modid - (OUT) module identifier 321 * port - (OUT) port number 322 * id - (OUT) queue group or scheduler identifier 323 * node - (OUT) node structure for the specified GPORT 324 * Returns: 325 * BCM_E_XXX 326 */ 327 STATIC int 328 bcmi_gh2_cosq_node_get(int unit, bcm_gport_t gport, bcm_cos_queue_t cosq, 329 bcm_module_t *modid, bcm_port_t *port, 330 int *id, gh2_cosq_node_t **node) 331 { 332 gh2_mmu_info_t *mmu_info; 333 gh2_cosq_node_t *node_base = NULL; 334 bcm_module_t modid_out = 0; 335 bcm_port_t port_out = 0; 336 uint32 encap_id = -1; 337 int index; 338 339 if ((mmu_info = gh2_mmu_info[unit]) == NULL) { 340 return BCM_E_INIT; 341 } 342 343 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 344 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &modid_out)); 345 port_out = BCM_GPORT_UCAST_QUEUE_GROUP_SYSPORTID_GET(gport); 346 } else if (BCM_GPORT_IS_SCHEDULER(gport)) { 347 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &modid_out)); 348 port_out = BCM_GPORT_SCHEDULER_GET(gport) & 0xff; 349 } else { 350 return BCM_E_PORT; 351 } 352 353 if (!SOC_PORT_VALID(unit, port_out)) { 354 return BCM_E_PORT; 355 } 356 357 if (port != NULL) { 358 *port = port_out; 359 } 360 361 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 362 encap_id = BCM_GPORT_UCAST_QUEUE_GROUP_QID_GET(gport); 363 index = encap_id; 364 node_base = mmu_info->queue_node; 365 } else { /* scheduler */ 366 encap_id = (BCM_GPORT_SCHEDULER_GET(gport) >> 8) & 0x3fff; 367 index = encap_id; 368 node_base = mmu_info->sched_node; 369 } 370 371 if (node_base[index].in_use == FALSE) { 372 return BCM_E_NOT_FOUND; 373 } 374 375 if (modid != NULL) { 376 *modid = modid_out; 377 } 378 if (id != NULL) { 379 *id = encap_id; 380 } 381 if (node != NULL) { 382 *node = &node_base[index]; 383 } 384 385 return BCM_E_NONE; 386 } 387 388 /* 389 * Function: 390 * bcmi_gh2_cosq_index_resolve 391 * Purpose: 392 * Find hardware index for the given gport 393 * Parameters: 394 * unit - (IN) unit number 395 * gport - (IN) GPORT identifier 396 * cosq - (OUT) result cosq of hw index 397 * Returns: 398 * BCM_E_XXX 399 */ 400 int 401 bcmi_gh2_cosq_index_resolve(int unit, bcm_gport_t gport, int *cosq) 402 { 403 gh2_cosq_node_t *node, *parent_node; 404 int cosq_base; 405 int cosq_offset; 406 407 if (gh2_mmu_info[unit] == NULL) { 408 return BCM_E_INIT; 409 } 410 411 if (cosq == NULL) { 412 return BCM_E_PARAM; 413 } 414 415 if (!BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 416 /* HW cosq index is only available Queue node */ 417 return BCM_E_PORT; 418 } 419 420 BCM_IF_ERROR_RETURN 421 (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL, 422 NULL, NULL, &node)); 423 424 if (node != NULL) { 425 cosq_offset = node->child_idx; 426 BCM_IF_ERROR_RETURN 427 (bcmi_gh2_cosq_node_get(unit, node->parent_gport, 0, NULL, 428 NULL, NULL, &parent_node)); 429 cosq_base = parent_node->qlayer_cosq_min; 430 *cosq = cosq_base + cosq_offset; 431 } else { 432 return BCM_E_NOT_FOUND; 433 } 434 435 return BCM_E_NONE; 436 } 437 438 /* 439 * Function: 440 * bcmi_gh2_cosq_port_resolve 441 * Purpose: 442 * Resolve gport and get IDs 443 * Parameters: 444 * unit - (IN) unit number 445 * gport - (IN) GPORT identifier 446 * modid - (OUT) module id 447 * port - (OUT) local port id 448 * trunk_id - (OUT) trunk id 449 * id - (OUT) Queue node or scheduler identifier 450 * Returns: 451 * BCM_E_XXX 452 */ 453 int 454 bcmi_gh2_cosq_port_resolve(int unit, bcm_gport_t gport, bcm_module_t *modid, 455 bcm_port_t *port, bcm_trunk_t *trunk_id, int *id) 456 { 457 gh2_cosq_node_t *node; 458 459 BCM_IF_ERROR_RETURN 460 (bcmi_gh2_cosq_node_get(unit, gport, 0, modid, port, id, &node)); 461 *trunk_id = -1; 462 463 return BCM_E_NONE; 464 } 465 466 /* 467 * Function: 468 * bcmi_gh2_cosq_localport_resolve 469 * Purpose: 470 * Resolve GRPOT if it is a local port 471 * Parameters: 472 * unit - (IN) unit number 473 * gport - (IN) GPORT identifier 474 * local_port - (OUT) local port number 475 * Returns: 476 * BCM_E_XXX 477 */ 478 STATIC int 479 bcmi_gh2_cosq_localport_resolve(int unit, bcm_gport_t gport, 480 bcm_port_t *local_port) 481 { 482 bcm_module_t module; 483 bcm_port_t port; 484 bcm_trunk_t trunk; 485 int id, result; 486 487 if (!BCM_GPORT_IS_SET(gport)) { 488 if (!SOC_PORT_VALID(unit, gport)) { 489 return BCM_E_PORT; 490 } 491 *local_port = gport; 492 return BCM_E_NONE; 493 } 494 495 BCM_IF_ERROR_RETURN 496 (_bcm_esw_gport_resolve(unit, gport, &module, 497 &port, &trunk, &id)); 498 BCM_IF_ERROR_RETURN( 499 _bcm_esw_modid_is_local(unit, module, &result)); 500 501 if (TRUE != result) { 502 return BCM_E_PARAM; 503 } 504 505 *local_port = port; 506 return BCM_E_NONE; 507 } 508 509 /* 510 * Function: 511 * bcmi_gh2_cosq_gport_bandwidth_port_resolve 512 * Purpose: 513 * Resolve GRPOT and cosq to get the cosq range for programming 514 * Parameters: 515 * unit - (IN) unit number 516 * gport - (IN) GPORT identifier 517 * cosq - (IN) cosq id 518 * local_port - (OUT) local port number 519 * cosq_start - (OUT) start index 520 * cosq_end - (OUT) end index 521 * Returns: 522 * BCM_E_XXX 523 */ 524 STATIC int 525 bcmi_gh2_cosq_gport_bandwidth_port_resolve(int unit, bcm_gport_t gport, 526 bcm_cos_queue_t cosq, 527 bcm_port_t *local_port, 528 bcm_cos_queue_t *cosq_start, 529 bcm_cos_queue_t *cosq_end) 530 { 531 int is_64q; 532 gh2_cosq_node_t *node = NULL; 533 534 if (gh2_mmu_info[unit] == NULL) { 535 return BCM_E_INIT; 536 } 537 538 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 539 /* shaping is supported on scheduler node */ 540 return BCM_E_PORT; 541 } 542 543 /* 544 * gport is local port: 545 * cosq range is 0~7 546 * gport is GPORT_SCHEDULER QGROUP 547 * cosq(num of qlayer cosq of the qgroup) range is 0~7 548 * gport is GPORT_SCHEDULER QLAYER 549 * cosq(num of qlayer cosq of the port) range is 0~7 550 */ 551 if (BCM_GPORT_IS_SET(gport)) { 552 if (BCM_GPORT_IS_SCHEDULER(gport)) { 553 BCM_IF_ERROR_RETURN 554 (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL, 555 local_port, NULL, &node)); 556 } else { 557 BCM_IF_ERROR_RETURN 558 (bcm_esw_port_local_get(unit, gport, local_port)); 559 } 560 } else { 561 *local_port = gport; 562 if (!SOC_PORT_VALID(unit, gport)) { 563 return BCM_E_PORT; 564 } 565 } 566 567 if (node != NULL) { 568 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, *local_port, 569 &is_64q)); 570 if (!is_64q) { 571 return BCM_E_PORT; 572 } 573 574 if (cosq < -1) { 575 return BCM_E_PARAM; 576 } 577 if (node->node_level == GH2_COSQ_LEVEL_QGROUP) { 578 if (cosq >= SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM) { 579 return BCM_E_PARAM; 580 } else if (cosq < 0) { 581 *cosq_start = 0; 582 *cosq_end = SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM - 1; 583 } else { 584 *cosq_start = *cosq_end = cosq; 585 } 586 } else { 587 /* node->node_level is GH2_COSQ_LEVEL_QLAYER */ 588 if (cosq >= gh2_num_cosq[unit]) { 589 return BCM_E_PARAM; 590 } else if (cosq < 0) { 591 *cosq_start = 0; 592 *cosq_end = gh2_num_cosq[unit] - 1; 593 } else { 594 *cosq_start = *cosq_end = cosq; 595 } 596 } 597 } else { 598 if (cosq < -1) { 599 return BCM_E_PARAM; 600 } 601 if (cosq >= gh2_num_cosq[unit]) { 602 return BCM_E_PARAM; 603 } else if (cosq < 0) { 604 *cosq_start = 0; 605 *cosq_end = gh2_num_cosq[unit] - 1; 606 } else { 607 *cosq_start = *cosq_end = cosq; 608 } 609 } 610 611 return BCM_E_NONE; 612 } 613 614 /* 615 * Function: 616 * bcmi_gh2_cosq_qlayer_scheduler_resolve 617 * Purpose: 618 * Find hardware cosq index and local port for the given gport 619 * The function only resolve QLayer scheduler gport type 620 * Parameters: 621 * unit - (IN) unit number 622 * gport - (IN) GPORT identifier, 623 * accept QLayer scheduler gport or local port id 624 * cosq - (IN) cosq id or input id, valid 0~7 625 * out_port - (OUT) local port id resolved 626 * out_hw_idx- (OUT) cosq of hw index resolved 627 * Returns: 628 * BCM_E_XXX 629 */ 630 STATIC int 631 bcmi_gh2_cosq_qlayer_scheduler_resolve(int unit, bcm_gport_t gport, 632 bcm_cos_queue_t cosq, 633 bcm_port_t *out_port, int *out_hw_idx) 634 { 635 bcm_gport_t local_gport; 636 int is_64q_port = 0; 637 gh2_cosq_node_t *node = NULL; 638 639 LOG_INFO(BSL_LS_BCM_COSQ, 640 (BSL_META_U(unit, 641 "bcmi_gh2_cosq_qlayer_scheduler_resolve: unit=%d \ 642 gport=0x%x cosq=%d\n"), 643 unit, gport, cosq)); 644 645 /* Get the local port and cosq hw index */ 646 if (BCM_GPORT_IS_SCHEDULER(gport)) { 647 /* The gport id is a Scheduler node */ 648 BCM_IF_ERROR_RETURN 649 (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL, NULL, NULL, 650 &node)); 651 /* Only accept QLAYER scheduler in this case */ 652 if (node->node_level != GH2_COSQ_LEVEL_QLAYER) { 653 return BCM_E_PORT; 654 } 655 656 /* Get the child gport of the QLAYER scheduler */ 657 BCM_IF_ERROR_RETURN 658 (bcmi_gh2_cosq_gport_child_get(unit, gport, cosq, 659 &local_gport)); 660 /* Get the hw cosq index (0~63) */ 661 BCM_IF_ERROR_RETURN 662 (bcmi_gh2_cosq_index_resolve(unit, local_gport, out_hw_idx)); 663 } else { 664 local_gport = gport; 665 /* Get the hw cosq index (0~7) */ 666 *out_hw_idx = cosq; 667 } 668 669 /* Get the local port id */ 670 BCM_IF_ERROR_RETURN 671 (bcmi_gh2_cosq_localport_resolve(unit, local_gport, out_port)); 672 673 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, *out_port, 674 &is_64q_port)); 675 if (is_64q_port) { 676 if ((*out_hw_idx < 0) || 677 (*out_hw_idx >= SOC_GH2_2LEVEL_QUEUE_NUM)) { 678 return BCM_E_PARAM; 679 } 680 } else { 681 if ((*out_hw_idx < 0) || 682 (*out_hw_idx >= SOC_GH2_LEGACY_QUEUE_NUM)) { 683 return BCM_E_PARAM; 684 } 685 } 686 687 LOG_INFO(BSL_LS_BCM_COSQ, 688 (BSL_META_U(unit, 689 "bcmi_gh2_cosq_qlayer_scheduler_resolve: unit=%d \ 690 out_port=0x%x out_hw_idx=%d\n"), 691 unit, *out_port, *out_hw_idx)); 692 return BCM_E_NONE; 693 } 694 695 STATIC int 696 bcmi_gh2_cosq_perq_xmt_counter_base_init(int unit) 697 { 698 uint32 regval32 = 0; 699 soc_port_t port = 0; 700 int base_index = 0, max_index = 0; 701 702 max_index = soc_mem_index_max(unit, EGR_PERQ_XMT_COUNTERSm); 703 704 PBMP_ALL_ITER(unit, port) { 705 /* Get the index of MMU_MAX/MIN_BUCKET_QLAYER table by (port, cosq) */ 706 BCM_IF_ERROR_RETURN( 707 soc_gh2_mmu_bucket_qlayer_index(unit, port, 0, &base_index)); 708 709 if (base_index > max_index) { 710 LOG_ERROR(BSL_LS_BCM_COSQ, 711 (BSL_META_U(unit, 712 "bcmi_gh2_cosq_perq_xmt_counter_base_init " 713 "error\n"))); 714 return BCM_E_RESOURCE; 715 } 716 717 BCM_IF_ERROR_RETURN( 718 READ_PERQ_XMT_COUNTER_BASEr(unit, port, ®val32)); 719 720 soc_reg_field_set(unit, PERQ_XMT_COUNTER_BASEr, 721 ®val32, INDEXf, base_index); 722 723 BCM_IF_ERROR_RETURN( 724 WRITE_PERQ_XMT_COUNTER_BASEr(unit, port, regval32)); 725 } 726 727 return BCM_E_NONE; 728 } 729 730 /* Function: 731 * bcmi_gh2_cosq_init 732 * Purpose: 733 * Initialize (clear) all COS schedule/mapping state. 734 * Parameters: 735 * unit - StrataSwitch unit number. 736 * Returns: 737 * BCM_E_XXX 738 */ 739 740 int 741 bcmi_gh2_cosq_init(int unit) 742 { 743 STATIC int _gh2_max_cosq = -1; 744 int num_cos = 0; 745 #ifdef BCM_WARM_BOOT_SUPPORT 746 int rv; 747 soc_scache_handle_t scache_handle; 748 uint32 cosq_scache_size; 749 uint8 *cosq_scache_ptr; 750 #endif /* BCM_WARM_BOOT_SUPPORT */ 751 752 static soc_mem_t wred_mems[6] = { 753 MMU_WRED_DROP_PROFILE_GREENm, 754 MMU_WRED_DROP_PROFILE_YELLOWm, 755 MMU_WRED_DROP_PROFILE_REDm, 756 MMU_WRED_MARK_PROFILE_GREENm, 757 MMU_WRED_MARK_PROFILE_YELLOWm, 758 MMU_WRED_MARK_PROFILE_REDm 759 }; 760 uint32 interval; 761 int entry_words[6]; 762 gh2_mmu_info_t *mmu_info; 763 int alloc_size; 764 int i; 765 766 if (_gh2_max_cosq < 0) { 767 _gh2_max_cosq = NUM_COS(unit); 768 NUM_COS(unit) = 8; 769 } 770 771 if (!SOC_WARM_BOOT(unit)) { /* Cold Boot */ 772 BCM_IF_ERROR_RETURN(bcmi_gh2_cosq_detach(unit, 0)); 773 if (soc_feature(unit, soc_feature_discard_ability)) { 774 BCM_IF_ERROR_RETURN( 775 soc_mem_clear(unit, MMU_WRED_CONFIGm, COPYNO_ALL, TRUE)); 776 BCM_IF_ERROR_RETURN( 777 soc_mem_clear(unit, MMU_WRED_CONFIG_QGROUPm, COPYNO_ALL, TRUE)); 778 } 779 } 780 781 num_cos = _bcm_esw_cosq_config_property_get(unit); 782 783 alloc_size = sizeof(gh2_mmu_info_t) * 1; 784 if (gh2_mmu_info[unit] == NULL) { 785 gh2_mmu_info[unit] = 786 sal_alloc(alloc_size, "gh2_mmu_info"); 787 788 if (gh2_mmu_info[unit] == NULL) { 789 return BCM_E_MEMORY; 790 } 791 792 sal_memset(gh2_mmu_info[unit], 0, alloc_size); 793 } 794 795 mmu_info = gh2_mmu_info[unit]; 796 797 for (i = 0; i < GH2_NUM_TOTAL_SCHEDULERS; i++) { 798 bcmi_gh2_cosq_node_t_init(&mmu_info->sched_node[i]); 799 } 800 801 for (i = 0; i < GH2_NUM_TOTAL_QUEUES; i++) { 802 bcmi_gh2_cosq_node_t_init(&mmu_info->queue_node[i]); 803 } 804 805 if (soc_feature(unit, soc_feature_discard_ability)) { 806 /* Create profile for MMU_WRED_DROP_CURVE_PROFILE_x tables */ 807 if (gh2_wred_profile[unit] == NULL) { 808 gh2_wred_profile[unit] = 809 sal_alloc(sizeof(soc_profile_mem_t), "WRED Profile Mem"); 810 if (gh2_wred_profile[unit] == NULL) { 811 return BCM_E_MEMORY; 812 } 813 soc_profile_mem_t_init(gh2_wred_profile[unit]); 814 } else { 815 soc_profile_mem_destroy(unit, gh2_wred_profile[unit]); 816 } 817 818 entry_words[0] = 819 sizeof(mmu_wred_drop_profile_green_entry_t) / sizeof(uint32); 820 entry_words[1] = 821 sizeof(mmu_wred_drop_profile_yellow_entry_t) / sizeof(uint32); 822 entry_words[2] = 823 sizeof(mmu_wred_drop_profile_red_entry_t) / sizeof(uint32); 824 entry_words[3] = 825 sizeof(mmu_wred_mark_profile_green_entry_t) / sizeof(uint32); 826 entry_words[4] = 827 sizeof(mmu_wred_mark_profile_yellow_entry_t) / sizeof(uint32); 828 entry_words[5] = 829 sizeof(mmu_wred_mark_profile_red_entry_t) / sizeof(uint32); 830 BCM_IF_ERROR_RETURN 831 (soc_profile_mem_create(unit, wred_mems, entry_words, 6, 832 gh2_wred_profile[unit])); 833 834 /* 835 * WRED update inetrval 836 * = 1040entries * core_clk_cycle_time * 1.125(sbus overhead), 837 * = 1170 * core_clk_cycle_time 838 * = 1170 / core_frequency 839 * 840 * GH2: 841 * 200M : interval=5 842 * 300M : interval=3 843 * 400M : interval=2 844 * 500M : interval=2 845 * 600M : interval=1 846 */ 847 interval = 1170 / SOC_INFO(unit).frequency; 848 BCM_IF_ERROR_RETURN( 849 soc_reg_field32_modify(unit, TIME_DOMAINr, 850 REG_PORT_ANY, WRED_UPDATE_INTERVALf, 851 interval)); 852 gh2_wred_update_interval[unit] = interval + 1; 853 } 854 855 /* Need to configure the base id within EGR_PERQ_XMT_COUNTERSm per port */ 856 BCM_IF_ERROR_RETURN( 857 bcmi_gh2_cosq_perq_xmt_counter_base_init(unit)); 858 859 #ifdef BCM_WARM_BOOT_SUPPORT 860 if (SOC_WARM_BOOT(unit)) { 861 BCM_IF_ERROR_RETURN(bcmi_gh2_cosq_reinit(unit)); 862 num_cos = gh2_num_cosq[unit]; 863 } else { 864 /* Warm boot level 2 cache size */ 865 cosq_scache_size = sizeof(uint32); /* Number COSQ */ 866 cosq_scache_size += sizeof(gh2_mmu_info_t); 867 868 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 0); 869 rv = _bcm_esw_scache_ptr_get(unit, scache_handle, 870 (0 == SOC_WARM_BOOT(unit)), 871 cosq_scache_size, &cosq_scache_ptr, 872 BCM_WB_DEFAULT_VERSION, NULL); 873 if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) { 874 return rv; 875 } 876 } 877 #endif /* BCM_WARM_BOOT_SUPPORT */ 878 879 return bcmi_gh2_cosq_config_set(unit, num_cos); 880 } 881 882 /* 883 * Function: 884 * bcmi_gh2_cosq_detach 885 * Purpose: 886 * Discard all COS schedule/mapping state. 887 * Parameters: 888 * unit - StrataSwitch unit number. 889 * Returns: 890 * BCM_E_XXX 891 */ 892 893 int 894 bcmi_gh2_cosq_detach(int unit, int software_state_only) 895 { 896 bcm_port_t port; 897 bcm_pbmp_t port_all; 898 int weights[8]; 899 int cosq; 900 int is_64q = 0; 901 uint32 reg_val; 902 903 if (gh2_mmu_info[unit]) { 904 sal_free(gh2_mmu_info[unit]); 905 gh2_mmu_info[unit] = NULL; 906 } 907 908 for (cosq = 0; cosq < 8; cosq++) { 909 weights[cosq] = 0; 910 } 911 912 if (!software_state_only) { 913 /* clear shaper tables */ 914 BCM_IF_ERROR_RETURN( 915 soc_mem_clear(unit, MMU_MAX_BUCKET_QLAYERm, MEM_BLOCK_ALL, 0)); 916 BCM_IF_ERROR_RETURN( 917 soc_mem_clear(unit, MMU_MIN_BUCKET_QLAYERm, MEM_BLOCK_ALL, 0)); 918 BCM_IF_ERROR_RETURN( 919 soc_mem_clear(unit, MMU_MAX_BUCKET_QGROUPm, MEM_BLOCK_ALL, 0)); 920 BCM_IF_ERROR_RETURN( 921 soc_mem_clear(unit, MMU_MIN_BUCKET_QGROUPm, MEM_BLOCK_ALL, 0)); 922 923 /* disable 2-level scheduling register */ 924 PBMP_ALL_ITER(unit, port) { 925 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, port, 926 &is_64q)); 927 if (is_64q) { 928 READ_TWO_LAYER_SCH_MODEr(unit, port, ®_val); 929 soc_reg_field_set(unit, TWO_LAYER_SCH_MODEr, ®_val, 930 SCH_MODEf, 0); 931 WRITE_TWO_LAYER_SCH_MODEr(unit, port, reg_val); 932 } 933 } 934 /* Clear scheduling settings on port */ 935 port_all = PBMP_ALL(unit); 936 BCM_IF_ERROR_RETURN 937 (bcmi_gh2_cosq_port_sched_set(unit, port_all, 938 BCM_COSQ_WEIGHTED_ROUND_ROBIN, 939 weights, 0)); 940 } 941 942 return BCM_E_NONE; 943 } 944 945 /* 946 * Function: 947 * bcmi_gh2_cosq_config_set 948 * Purpose: 949 * Set the number of COS queues 950 * Parameters: 951 * unit - Unit number. 952 * numq - number of COS queues (1-8). 953 * Returns: 954 * BCM_E_XXX 955 */ 956 957 int 958 bcmi_gh2_cosq_config_set(int unit, int numq) 959 { 960 int cos, prio, ratio, remain; 961 uint32 index; 962 soc_mem_t mem = PORT_COS_MAPm; 963 int entry_words = sizeof(port_cos_map_entry_t) / sizeof(uint32); 964 bcm_pbmp_t ports; 965 bcm_port_t port; 966 port_cos_map_entry_t cos_map_array[GH2_COS_MAP_ENTRIES_PER_SET]; 967 void *entries[GH2_COS_MAP_ENTRIES_PER_SET]; 968 static soc_mem_t wred_mems[6] = { 969 MMU_WRED_DROP_PROFILE_GREENm, 970 MMU_WRED_DROP_PROFILE_YELLOWm, 971 MMU_WRED_DROP_PROFILE_REDm, 972 MMU_WRED_MARK_PROFILE_GREENm, 973 MMU_WRED_MARK_PROFILE_YELLOWm, 974 MMU_WRED_MARK_PROFILE_REDm 975 }; 976 int ii, wred_prof_count; 977 uint32 profile_index; 978 mmu_wred_drop_profile_green_entry_t entry_tcp_green; 979 mmu_wred_drop_profile_yellow_entry_t entry_tcp_yellow; 980 mmu_wred_drop_profile_red_entry_t entry_tcp_red; 981 mmu_wred_mark_profile_green_entry_t entry_mark_green; 982 mmu_wred_mark_profile_yellow_entry_t entry_mark_yellow; 983 mmu_wred_mark_profile_red_entry_t entry_mark_red; 984 void *wred_entries[6]; 985 986 /* Validate cosq num */ 987 if (numq < 1) { 988 return BCM_E_PARAM; 989 } 990 991 /* Map the eight 802.1 priority levels to the active cosqs */ 992 if (numq > 8) { 993 numq = 8; 994 } 995 996 sal_memset(cos_map_array, 0, 997 GH2_COS_MAP_ENTRIES_PER_SET * sizeof(port_cos_map_entry_t)); 998 999 if (gh2_cos_map_profile[unit] == NULL) { 1000 gh2_cos_map_profile[unit] = sal_alloc(sizeof(soc_profile_mem_t), 1001 "COS_MAP Profile Mem"); 1002 if (gh2_cos_map_profile[unit] == NULL) { 1003 return BCM_E_MEMORY; 1004 } 1005 soc_profile_mem_t_init(gh2_cos_map_profile[unit]); 1006 } 1007 1008 /* Create profile table cache (or re-init if it already exists) */ 1009 SOC_IF_ERROR_RETURN(soc_profile_mem_create(unit, &mem, &entry_words, 1, 1010 gh2_cos_map_profile[unit])); 1011 1012 if (SOC_WARM_BOOT(unit)) { /* Warm Boot */ 1013 int i; 1014 uint32 val; 1015 1016 /* Gather reference count for cosq map profile table */ 1017 BCM_PBMP_ASSIGN(ports, PBMP_ALL(unit)); 1018 PBMP_ITER(ports, port) { 1019 SOC_IF_ERROR_RETURN(READ_COS_MAP_SELr(unit, port, &val)); 1020 index = soc_reg_field_get(unit, COS_MAP_SELr, val, SELECTf); 1021 index *= GH2_COS_MAP_ENTRIES_PER_SET; 1022 for (i = 0; i < GH2_COS_MAP_ENTRIES_PER_SET; i++) { 1023 SOC_PROFILE_MEM_REFERENCE(unit, gh2_cos_map_profile[unit], 1024 index + i, 1); 1025 SOC_PROFILE_MEM_ENTRIES_PER_SET(unit, 1026 gh2_cos_map_profile[unit], 1027 index + i, 1028 GH2_COS_MAP_ENTRIES_PER_SET); 1029 } 1030 #ifndef BCM_COSQ_HIGIG_MAP_DISABLE 1031 if (IS_HG_PORT(unit, port) || port == CMIC_PORT(unit)) { 1032 SOC_IF_ERROR_RETURN(READ_ICOS_MAP_SELr(unit, port, &val)); 1033 index = soc_reg_field_get(unit, ICOS_MAP_SELr, val, SELECTf); 1034 index *= GH2_COS_MAP_ENTRIES_PER_SET; 1035 for (i = 0; i < GH2_COS_MAP_ENTRIES_PER_SET; i++) { 1036 SOC_PROFILE_MEM_REFERENCE(unit, gh2_cos_map_profile[unit], 1037 index + i, 1); 1038 SOC_PROFILE_MEM_ENTRIES_PER_SET( 1039 unit, 1040 gh2_cos_map_profile[unit], 1041 index + i, 1042 GH2_COS_MAP_ENTRIES_PER_SET); 1043 } 1044 } 1045 #endif /* BCM_COSQ_HIGIG_MAP_DISABLE */ 1046 } 1047 1048 gh2_num_cosq[unit] = numq; 1049 1050 return BCM_E_NONE; 1051 } 1052 1053 /* Cold Boot */ 1054 ratio = 8 / numq; 1055 remain = 8 % numq; 1056 cos = 0; 1057 for (prio = 0; prio < 8; prio++) { 1058 soc_mem_field32_set(unit, PORT_COS_MAPm, 1059 &cos_map_array[prio], COSf, cos); 1060 if (soc_mem_field_valid(unit, PORT_COS_MAPm, HG_COSf)) { 1061 soc_mem_field32_set(unit, PORT_COS_MAPm, 1062 &cos_map_array[prio], HG_COSf, 0); 1063 } 1064 1065 if ((prio + 1) == (((cos + 1) * ratio) + 1066 ((remain < (numq - cos)) ? 0 : 1067 (remain - (numq - cos) + 1)))) { 1068 cos++; 1069 } 1070 entries[prio] = (void *) &cos_map_array[prio]; 1071 } 1072 1073 /* Map remaining internal priority levels to highest priority cosq */ 1074 cos = numq - 1; 1075 for (prio = 8; prio < 16; prio++) { 1076 soc_mem_field32_set(unit, PORT_COS_MAPm, 1077 &cos_map_array[prio], COSf, cos); 1078 if (soc_mem_field_valid(unit, PORT_COS_MAPm, HG_COSf)) { 1079 soc_mem_field32_set(unit, PORT_COS_MAPm, 1080 &cos_map_array[prio], HG_COSf, 0); 1081 } 1082 entries[prio] = (void *) &cos_map_array[prio]; 1083 } 1084 1085 /* Map internal priority levels to CPU CoS queues */ 1086 BCM_IF_ERROR_RETURN(_bcm_esw_cpu_cosq_mapping_default_set(unit, numq)); 1087 1088 /* Add a profile mem entry for each port */ 1089 BCM_PBMP_ASSIGN(ports, PBMP_ALL(unit)); 1090 PBMP_ITER(ports, port) { 1091 SOC_IF_ERROR_RETURN 1092 (soc_profile_mem_add(unit, gh2_cos_map_profile[unit], 1093 (void *) &entries, 1094 GH2_COS_MAP_ENTRIES_PER_SET, &index)); 1095 SOC_IF_ERROR_RETURN 1096 (soc_reg_field32_modify(unit, COS_MAP_SELr, port, 1097 SELECTf, 1098 (index / GH2_COS_MAP_ENTRIES_PER_SET))); 1099 #ifndef BCM_COSQ_HIGIG_MAP_DISABLE 1100 if (IS_HG_PORT(unit, port) || port == CMIC_PORT(unit)) { 1101 SOC_IF_ERROR_RETURN 1102 (soc_profile_mem_add(unit, gh2_cos_map_profile[unit], 1103 (void *) &entries, 1104 GH2_COS_MAP_ENTRIES_PER_SET, &index)); 1105 SOC_IF_ERROR_RETURN 1106 (soc_reg_field32_modify(unit, ICOS_MAP_SELr, port, 1107 SELECTf, 1108 (index / GH2_COS_MAP_ENTRIES_PER_SET))); 1109 } 1110 #endif 1111 } 1112 1113 #ifdef BCM_COSQ_HIGIG_MAP_DISABLE 1114 /* identity mapping for higig ports */ 1115 1116 /* map prio0->cos0, prio1->cos1, ... , prio7->cos7 */ 1117 for (prio = 0; prio < 8; prio++) { 1118 soc_mem_field32_set(unit, PORT_COS_MAPm, 1119 &cos_map_array[prio], COSf, prio); 1120 if (soc_mem_field_valid(unit, PORT_COS_MAPm, HG_COSf)) { 1121 soc_mem_field32_set(unit, PORT_COS_MAPm, 1122 &cos_map_array[prio], HG_COSf, 0); 1123 } 1124 } 1125 /* Map remaining internal priority levels to highest priority cosq */ 1126 for (prio = 8; prio < 16; prio++) { 1127 soc_mem_field32_set(unit, PORT_COS_MAPm, 1128 &cos_map_array[prio], COSf, 7); 1129 if (soc_mem_field_valid(unit, PORT_COS_MAPm, HG_COSf)) { 1130 soc_mem_field32_set(unit, PORT_COS_MAPm, 1131 &cos_map_array[prio], HG_COSf, 0); 1132 } 1133 } 1134 PBMP_ITER(ports, port) { 1135 if (IS_HG_PORT(unit, port) || port == CMIC_PORT(unit)) { 1136 SOC_IF_ERROR_RETURN 1137 (soc_profile_mem_add(unit, gh2_cos_map_profile[unit], 1138 (void *) &entries, 1139 GH2_COS_MAP_ENTRIES_PER_SET, &index)); 1140 soc_reg_field32_modify(unit, ICOS_MAP_SELr, port, 1141 SELECTf, 1142 (index / GH2_COS_MAP_ENTRIES_PER_SET)); 1143 } 1144 } 1145 #endif 1146 1147 gh2_num_cosq[unit] = numq; 1148 1149 if (soc_feature(unit, soc_feature_discard_ability)) { 1150 /* Add default entries for MMU_WRED_DROP_CURVE_PROFILE_x memory profile */ 1151 sal_memset(&entry_tcp_green, 0, sizeof(entry_tcp_green)); 1152 sal_memset(&entry_tcp_yellow, 0, sizeof(entry_tcp_yellow)); 1153 sal_memset(&entry_tcp_red, 0, sizeof(entry_tcp_red)); 1154 sal_memset(&entry_mark_green, 0, sizeof(entry_mark_green)); 1155 sal_memset(&entry_mark_yellow, 0, sizeof(entry_mark_yellow)); 1156 sal_memset(&entry_mark_red, 0, sizeof(entry_mark_red)); 1157 wred_entries[0] = &entry_tcp_green; 1158 wred_entries[1] = &entry_tcp_yellow; 1159 wred_entries[2] = &entry_tcp_red; 1160 wred_entries[3] = &entry_mark_green; 1161 wred_entries[4] = &entry_mark_yellow; 1162 wred_entries[5] = &entry_mark_red; 1163 for (ii = 0; ii < 6; ii++) { 1164 soc_mem_field32_set(unit, wred_mems[ii], wred_entries[ii], 1165 MIN_THDf, GH2_CELL_FIELD_MAX); 1166 soc_mem_field32_set(unit, wred_mems[ii], wred_entries[ii], 1167 MAX_THDf, GH2_CELL_FIELD_MAX); 1168 } 1169 profile_index = 0xffffffff; 1170 wred_prof_count = soc_mem_index_count(unit, MMU_WRED_CONFIGm); 1171 while (wred_prof_count) { 1172 if (profile_index == 0xffffffff) { 1173 BCM_IF_ERROR_RETURN 1174 (soc_profile_mem_add(unit, 1175 gh2_wred_profile[unit], 1176 wred_entries, 1, &profile_index)); 1177 } else { 1178 BCM_IF_ERROR_RETURN 1179 (soc_profile_mem_reference(unit, 1180 gh2_wred_profile[unit], 1181 profile_index, 0)); 1182 } 1183 wred_prof_count -= 1; 1184 } 1185 profile_index = 0xffffffff; 1186 wred_prof_count = 1187 soc_mem_index_count(unit, MMU_WRED_CONFIG_QGROUPm); 1188 while (wred_prof_count) { 1189 if (profile_index == 0xffffffff) { 1190 BCM_IF_ERROR_RETURN 1191 (soc_profile_mem_add(unit, 1192 gh2_wred_profile[unit], 1193 wred_entries, 1, &profile_index)); 1194 } else { 1195 BCM_IF_ERROR_RETURN 1196 (soc_profile_mem_reference(unit, 1197 gh2_wred_profile[unit], 1198 profile_index, 0)); 1199 } 1200 wred_prof_count -= 1; 1201 } 1202 1203 BCM_IF_ERROR_RETURN( 1204 _bcm_esw_ecn_init(unit)); 1205 1206 } 1207 1208 return BCM_E_NONE; 1209 } 1210 1211 /* 1212 * Function: 1213 * bcmi_gh2_cosq_config_get 1214 * Purpose: 1215 * Get the number of cos queues 1216 * Parameters: 1217 * unit - StrataSwitch unit number. 1218 * numq - (Output) number of cosq 1219 * Returns: 1220 * BCM_E_XXX 1221 */ 1222 1223 int 1224 bcmi_gh2_cosq_config_get(int unit, int *numq) 1225 { 1226 if (gh2_num_cosq[unit] == 0) { 1227 return BCM_E_INIT; 1228 } 1229 1230 if (numq != NULL) { 1231 *numq = gh2_num_cosq[unit]; 1232 } 1233 1234 return BCM_E_NONE; 1235 } 1236 1237 /* 1238 * Function: 1239 * bcmi_gh2_cosq_port_bandwidth_set 1240 * Purpose: 1241 * Set bandwidth values for given COS policy. 1242 * Parameters: 1243 * unit - StrataSwitch unit number. 1244 * port - port to configure 1245 * cosq - COS queue to configure 1246 * kbits_sec_min - minimum bandwidth, kbits/sec. 1247 * kbits_sec_max - maximum bandwidth, kbits/sec. 1248 * flags 1249 * Returns: 1250 * BCM_E_XXX 1251 */ 1252 int 1253 bcmi_gh2_cosq_port_bandwidth_set(int unit, bcm_gport_t gport, 1254 bcm_cos_queue_t cosq, 1255 uint32 kbits_sec_min, 1256 uint32 kbits_sec_max, 1257 uint32 kbits_sec_burst, 1258 uint32 flags) 1259 { 1260 uint32 regval, rval = 0; 1261 uint32 burst_size = 0; 1262 uint32 refresh_rate, bucketsize, granularity = 3, meter_flags = 0; 1263 int refresh_bitsize, bucket_bitsize; 1264 uint32 fval = 0; 1265 uint32 eav_gran = GH2_BURST_GRANULARITY_DEFAULT; 1266 int memidx; 1267 soc_mem_t config_mem = INVALIDm; 1268 soc_reg_t config_reg = INVALIDr; 1269 uint32 entry[SOC_MAX_MEM_WORDS]; 1270 int is_64q; 1271 int shift; 1272 bcm_port_t local_port; 1273 gh2_cosq_node_t *node = NULL; 1274 int local_cosq; 1275 soc_mem_t max_bucket_mem = INVALIDm; 1276 soc_mem_t min_bucket_mem = INVALIDm; 1277 soc_reg_t min_gran_reg = INVALIDr; 1278 soc_reg_t max_gran_reg = INVALIDr; 1279 int gran_shift = 0; 1280 soc_reg_t eav_bucket_reg = INVALIDr; 1281 1282 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 1283 /* shaping is supported on scheduler node */ 1284 return BCM_E_PORT; 1285 } 1286 1287 /* 1288 * Parameter gport cases 1289 * gport is local port: 1290 * parameter cosq valid : 0~7 1291 * gport is GPORT_SCHEDULER QGROUP 1292 * parameter cosq valid : 0~7 1293 * gport is GPORT_SCHEDULER QLAYER 1294 * parameter cosq valid : 0~7 1295 */ 1296 if (BCM_GPORT_IS_SCHEDULER(gport)) { 1297 BCM_IF_ERROR_RETURN 1298 (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL, 1299 &local_port, NULL, &node)); 1300 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port, 1301 &is_64q)); 1302 if (!is_64q) { 1303 return BCM_E_PORT; 1304 } 1305 if (node->node_level == GH2_COSQ_LEVEL_PORT) { 1306 /* Shaper is not available on this level */ 1307 return BCM_E_UNAVAIL; 1308 } else if (node->node_level == GH2_COSQ_LEVEL_QGROUP) { 1309 max_bucket_mem = MMU_MAX_BUCKET_QGROUPm; 1310 min_bucket_mem = MMU_MIN_BUCKET_QGROUPm; 1311 min_gran_reg = SHAPING_Q_GRAN_QGROUPr; 1312 max_gran_reg = SHAPING_Q_GRAN_QGROUPr; 1313 gran_shift = cosq; 1314 eav_bucket_reg = EAVBUCKETCONFIG_EXT_QGROUPr; 1315 } else { 1316 max_bucket_mem = MMU_MAX_BUCKET_QLAYERm; 1317 min_bucket_mem = MMU_MIN_BUCKET_QLAYERm; 1318 1319 /* transfered to hw queue index (0~63) */ 1320 local_cosq = node->qlayer_cosq_min + cosq; 1321 if (local_cosq < 32) { 1322 min_gran_reg = SHAPING_Q_GRAN_QLAYER_MIN0r; 1323 max_gran_reg = SHAPING_Q_GRAN_QLAYER_MAX0r; 1324 gran_shift = local_cosq; 1325 } else { 1326 min_gran_reg = SHAPING_Q_GRAN_QLAYER_MIN1r; 1327 max_gran_reg = SHAPING_Q_GRAN_QLAYER_MAX1r; 1328 gran_shift = local_cosq - 32; 1329 } 1330 1331 eav_bucket_reg = EAVBUCKETCONFIG_EXT_QLAYERr; 1332 } 1333 } else { 1334 BCM_IF_ERROR_RETURN 1335 (bcmi_gh2_cosq_localport_resolve(unit, gport, &local_port)); 1336 1337 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port, 1338 &is_64q)); 1339 1340 max_bucket_mem = MMU_MAX_BUCKET_QLAYERm; 1341 min_bucket_mem = MMU_MIN_BUCKET_QLAYERm; 1342 1343 if (is_64q) { 1344 if (cosq < 32) { 1345 min_gran_reg = SHAPING_Q_GRAN_QLAYER_MIN0r; 1346 max_gran_reg = SHAPING_Q_GRAN_QLAYER_MAX0r; 1347 gran_shift = cosq; 1348 } else { 1349 min_gran_reg = SHAPING_Q_GRAN_QLAYER_MIN1r; 1350 max_gran_reg = SHAPING_Q_GRAN_QLAYER_MAX1r; 1351 gran_shift = cosq - 32; 1352 } 1353 eav_bucket_reg = EAVBUCKETCONFIG_EXT_QLAYERr; 1354 } else { 1355 min_gran_reg = SHAPING_Q_GRANr; 1356 max_gran_reg = SHAPING_Q_GRANr; 1357 gran_shift = cosq; 1358 eav_bucket_reg = EAVBUCKETCONFIG_EXTr; 1359 } 1360 } 1361 1362 /* 1363 * To set the new Bandwidth settings, the procedure adopted is 1364 * a. reset MAXBUCKETCONFIG, MINBUCKETCONFIG, MAXBUCKET, MINBUCKET 1365 * b. update MAXBUCKETCONFIG and MINBUCKETCONFIG with new values passed 1366 * c. if MISCCONFIG.METERING_CLK_EN not set before, enable it. 1367 */ 1368 1369 if (node) { 1370 if (node->node_level == GH2_COSQ_LEVEL_QGROUP) { 1371 /* 1372 * Get the hw index of MMU_MAX/MIN_BUCKET_QGROUP table by 1373 * (port, cosq) 1374 */ 1375 BCM_IF_ERROR_RETURN( 1376 soc_gh2_mmu_bucket_qgroup_index(unit, 1377 local_port, 1378 cosq, 1379 &memidx)); 1380 } else { 1381 /* node->node_level is GH2_COSQ_LEVEL_QLAYER */ 1382 /* 1383 * Get the hw index of MMU_MAX/MIN_BUCKET_QLAYER table by 1384 * (port, cosq) 1385 */ 1386 BCM_IF_ERROR_RETURN( 1387 soc_gh2_mmu_bucket_qlayer_index(unit, 1388 local_port, 1389 node->qlayer_cosq_min + cosq, 1390 &memidx)); 1391 } 1392 } else { 1393 /* Get the index of MMU_MAX/MIN_BUCKET_QLAYER table by (port, cosq) */ 1394 BCM_IF_ERROR_RETURN(soc_gh2_mmu_bucket_qlayer_index 1395 (unit, local_port, cosq, &memidx)); 1396 } 1397 1398 /* Disable egress metering for this port */ 1399 config_mem = max_bucket_mem; /* MMU_MAX_BUCKET_QLAYERm; */ 1400 BCM_IF_ERROR_RETURN 1401 (soc_mem_read(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry)); 1402 soc_mem_field32_set(unit, config_mem, &entry, REFRESHf, 0); 1403 soc_mem_field32_set(unit, config_mem, &entry, THD_SELf, 0); 1404 BCM_IF_ERROR_RETURN 1405 (soc_mem_write(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry)); 1406 1407 config_mem = min_bucket_mem; /* MMU_MIN_BUCKET_QLAYERm; */ 1408 BCM_IF_ERROR_RETURN 1409 (soc_mem_read(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry)); 1410 soc_mem_field32_set(unit, config_mem, &entry, REFRESHf, 0); 1411 soc_mem_field32_set(unit, config_mem, &entry, THD_SELf, 0); 1412 BCM_IF_ERROR_RETURN 1413 (soc_mem_write(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry)); 1414 1415 /* reset the MAXBUCKET register */ 1416 config_mem = max_bucket_mem; /* MMU_MAX_BUCKET_QLAYERm; */ 1417 BCM_IF_ERROR_RETURN 1418 (soc_mem_read(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry)); 1419 soc_mem_field32_set(unit, config_mem, &entry, BUCKETf, 0); 1420 BCM_IF_ERROR_RETURN 1421 (soc_mem_write(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry)); 1422 1423 /* reset the MINBUCKET register value */ 1424 config_mem = min_bucket_mem; /* MMU_MIN_BUCKET_QLAYERm; */ 1425 BCM_IF_ERROR_RETURN 1426 (soc_mem_read(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry)); 1427 soc_mem_field32_set(unit, config_mem, &entry, BUCKETf, 0); 1428 BCM_IF_ERROR_RETURN 1429 (soc_mem_write(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry)); 1430 1431 1432 refresh_bitsize = 1433 soc_mem_field_length(unit, MMU_MIN_BUCKET_QLAYERm, REFRESHf); 1434 bucket_bitsize = 1435 soc_mem_field_length(unit, MMU_MIN_BUCKET_QLAYERm, THD_SELf); 1436 1437 meter_flags |= _BCM_XGS_METER_FLAG_GRANULARITY_SELECTIVE; 1438 meter_flags |= _BCM_XGS_METER_FLAG_GRANULARITY_SELECT3; 1439 meter_flags |= _BCM_XGS_METER_FLAG_GRANULARITY_SELECT5; 1440 meter_flags |= _BCM_XGS_METER_FLAG_BUCKET_IN_8KB; 1441 1442 BCM_IF_ERROR_RETURN 1443 (_bcm_xgs_kbits_to_bucket_encoding(kbits_sec_min, kbits_sec_min, 1444 meter_flags, refresh_bitsize, 1445 bucket_bitsize, 1446 &refresh_rate, &bucketsize, 1447 &granularity)); 1448 config_reg = min_gran_reg; 1449 shift = gran_shift; 1450 1451 BCM_IF_ERROR_RETURN 1452 (soc_reg32_get(unit, config_reg, local_port, 0, ®val)); 1453 fval = soc_reg_field_get(unit, config_reg, 1454 regval, MIN_Q_GRANf); 1455 if (granularity == 5) { 1456 fval |= (1 << shift); 1457 } else { 1458 fval &= ~(1 << shift); 1459 } 1460 soc_reg_field_set(unit, config_reg, ®val, 1461 MIN_Q_GRANf, fval); 1462 BCM_IF_ERROR_RETURN 1463 (soc_reg32_set(unit, config_reg, local_port, 0, regval)); 1464 1465 config_mem = min_bucket_mem; /* MMU_MIN_BUCKET_QLAYERm; */ 1466 BCM_IF_ERROR_RETURN 1467 (soc_mem_read(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry)); 1468 soc_mem_field32_set(unit, config_mem, &entry, REFRESHf, refresh_rate); 1469 soc_mem_field32_set(unit, config_mem, &entry, THD_SELf, bucketsize); 1470 BCM_IF_ERROR_RETURN 1471 (soc_mem_write(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry)); 1472 1473 1474 refresh_bitsize = 1475 soc_mem_field_length(unit, MMU_MAX_BUCKET_QLAYERm, REFRESHf); 1476 bucket_bitsize = 1477 soc_mem_field_length(unit, MMU_MAX_BUCKET_QLAYERm, THD_SELf); 1478 1479 BCM_IF_ERROR_RETURN 1480 (_bcm_xgs_kbits_to_bucket_encoding(kbits_sec_max, kbits_sec_burst, 1481 meter_flags, refresh_bitsize, 1482 bucket_bitsize, 1483 &refresh_rate, &bucketsize, 1484 &granularity)); 1485 config_reg = max_gran_reg; 1486 shift = gran_shift; 1487 1488 BCM_IF_ERROR_RETURN 1489 (soc_reg32_get(unit, config_reg, local_port, 0, ®val)); 1490 fval = soc_reg_field_get(unit, config_reg, 1491 regval, MAX_Q_GRANf); 1492 if (granularity == 5) { 1493 fval |= (1 << shift); 1494 } else { 1495 fval &= ~(1 << shift); 1496 } 1497 soc_reg_field_set(unit, config_reg, ®val, 1498 MAX_Q_GRANf, fval); 1499 BCM_IF_ERROR_RETURN 1500 (soc_reg32_set(unit, config_reg, local_port, 0, regval)); 1501 1502 config_mem = max_bucket_mem; /* MMU_MAX_BUCKET_QLAYERm; */ 1503 BCM_IF_ERROR_RETURN 1504 (soc_mem_read(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry)); 1505 1506 soc_mem_field32_set(unit, config_mem, &entry, REFRESHf, refresh_rate); 1507 if ((flags & (BCM_COSQ_BW_EAV_MODE | BCM_COSQ_BW_EAV_TAS_MODE)) == 1508 (BCM_COSQ_BW_EAV_MODE | BCM_COSQ_BW_EAV_TAS_MODE)) { 1509 return BCM_E_CONFIG; 1510 } 1511 if ((flags & BCM_COSQ_BW_EAV_MODE) || 1512 (flags & BCM_COSQ_BW_EAV_TAS_MODE)) { 1513 if (granularity == 5) { 1514 eav_gran = GH2_BURST_GRANULARITY_128B; 1515 } else { 1516 eav_gran = GH2_BURST_GRANULARITY_DEFAULT; 1517 } 1518 burst_size = (((kbits_sec_burst * 1000) / 8) + 1519 (eav_gran - 1)) / eav_gran; 1520 if (burst_size > GH2_BW_FIELD_MAX) { 1521 burst_size = GH2_BW_FIELD_MAX; 1522 } 1523 1524 if (flags & BCM_COSQ_BW_EAV_MODE) { 1525 soc_mem_field32_set(unit, config_mem, &entry, EAV_MODEf, 1); 1526 } else { 1527 soc_mem_field32_set(unit, config_mem, &entry, EAV_MODEf, 2); 1528 } 1529 config_reg = eav_bucket_reg; 1530 1531 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, config_reg, 1532 local_port, cosq, &rval)); 1533 soc_reg_field_set(unit, config_reg, &rval, EAV_THD_SEL_6LSBf, 1534 burst_size & 0x3f); 1535 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, config_reg, 1536 local_port, cosq, rval)); 1537 1538 soc_mem_field32_set(unit, config_mem, &entry, THD_SELf, 1539 (burst_size >> 6 & 0xFFF)); 1540 } else { 1541 soc_mem_field32_set(unit, config_mem, &entry, EAV_MODEf, 0); 1542 soc_mem_field32_set(unit, config_mem, &entry, THD_SELf, 1543 bucketsize); 1544 } 1545 BCM_IF_ERROR_RETURN 1546 (soc_mem_write(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry)); 1547 1548 config_reg = eav_bucket_reg; 1549 if (SOC_REG_FIELD_VALID(unit, config_reg, GATE_CLOSE_FREEZE_MODEf)) { 1550 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, config_reg, 1551 local_port, cosq, &rval)); 1552 if (flags & BCM_COSQ_BW_TAS_TOKEN_FREEZE) { 1553 soc_reg_field_set(unit, config_reg, &rval, GATE_CLOSE_FREEZE_MODEf, 1554 1); 1555 } else { 1556 soc_reg_field_set(unit, config_reg, &rval, GATE_CLOSE_FREEZE_MODEf, 1557 0); 1558 } 1559 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, config_reg, 1560 local_port, cosq, rval)); 1561 } 1562 1563 /* MISCCONFIG.METERING_CLK_EN is set by chip init */ 1564 1565 return BCM_E_NONE; 1566 } 1567 1568 /* 1569 * Function: 1570 * bcmi_gh2_cosq_port_bandwidth_get 1571 * Purpose: 1572 * Retrieve bandwidth values for given COS policy. 1573 * Parameters: 1574 * unit - StrataSwitch unit number. 1575 * port - port to configure 1576 * cosq - COS queue to configure 1577 * kbits_sec_min - (OUT) minimum bandwidth, kbits/sec. 1578 * kbits_sec_max - (OUT) maximum bandwidth, kbits/sec. 1579 * flags - (OUT) 1580 * Returns: 1581 * BCM_E_XXX 1582 */ 1583 int 1584 bcmi_gh2_cosq_port_bandwidth_get(int unit, bcm_gport_t gport, 1585 bcm_cos_queue_t cosq, 1586 uint32 *kbits_sec_min, 1587 uint32 *kbits_sec_max, 1588 uint32 *kbits_sec_burst, 1589 uint32 *flags) 1590 { 1591 uint32 regval; 1592 uint32 refresh_rate = 0, bucketsize = 0, 1593 granularity = 3, meter_flags = 0; 1594 uint32 kbits_min_burst; /* Placeholder, since burst is unused for min */ 1595 uint32 rval = 0; 1596 uint32 bucket_lo = 0; 1597 uint32 eav_mode = 0; 1598 uint32 fval = 0; 1599 uint32 eav_gran = GH2_BURST_GRANULARITY_DEFAULT; 1600 int memidx; 1601 int is_64q; 1602 int shift; 1603 soc_mem_t config_mem = INVALIDm; 1604 soc_reg_t config_reg = INVALIDr; 1605 uint32 entry[SOC_MAX_MEM_WORDS]; 1606 bcm_port_t local_port; 1607 gh2_cosq_node_t *node = NULL; 1608 int local_cosq; 1609 soc_mem_t max_bucket_mem = INVALIDm; 1610 soc_mem_t min_bucket_mem = INVALIDm; 1611 soc_reg_t min_gran_reg = INVALIDr; 1612 soc_reg_t max_gran_reg = INVALIDr; 1613 int gran_shift = 0; 1614 soc_reg_t eav_bucket_reg = INVALIDr; 1615 1616 if (BCM_GPORT_IS_SCHEDULER(gport)) { 1617 BCM_IF_ERROR_RETURN 1618 (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL, 1619 &local_port, NULL, &node)); 1620 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port, 1621 &is_64q)); 1622 if (!is_64q) { 1623 return BCM_E_PORT; 1624 } 1625 if (node->node_level == GH2_COSQ_LEVEL_PORT) { 1626 /* Shaper is not available on this level */ 1627 return BCM_E_UNAVAIL; 1628 } else if (node->node_level == GH2_COSQ_LEVEL_QGROUP) { 1629 max_bucket_mem = MMU_MAX_BUCKET_QGROUPm; 1630 min_bucket_mem = MMU_MIN_BUCKET_QGROUPm; 1631 min_gran_reg = SHAPING_Q_GRAN_QGROUPr; 1632 max_gran_reg = SHAPING_Q_GRAN_QGROUPr; 1633 gran_shift = cosq; 1634 eav_bucket_reg = EAVBUCKETCONFIG_EXT_QGROUPr; 1635 } else { 1636 max_bucket_mem = MMU_MAX_BUCKET_QLAYERm; 1637 min_bucket_mem = MMU_MIN_BUCKET_QLAYERm; 1638 1639 /* transfered to hw queue index (0~63) */ 1640 local_cosq = node->qlayer_cosq_min + cosq; 1641 if (local_cosq < 32) { 1642 min_gran_reg = SHAPING_Q_GRAN_QLAYER_MIN0r; 1643 max_gran_reg = SHAPING_Q_GRAN_QLAYER_MAX0r; 1644 gran_shift = local_cosq; 1645 } else { 1646 min_gran_reg = SHAPING_Q_GRAN_QLAYER_MIN1r; 1647 max_gran_reg = SHAPING_Q_GRAN_QLAYER_MAX1r; 1648 gran_shift = local_cosq - 32; 1649 } 1650 eav_bucket_reg = EAVBUCKETCONFIG_EXT_QLAYERr; 1651 } 1652 } else { 1653 BCM_IF_ERROR_RETURN 1654 (bcmi_gh2_cosq_localport_resolve(unit, gport, &local_port)); 1655 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port, 1656 &is_64q)); 1657 max_bucket_mem = MMU_MAX_BUCKET_QLAYERm; 1658 min_bucket_mem = MMU_MIN_BUCKET_QLAYERm; 1659 if (is_64q) { 1660 if (cosq < 32) { 1661 min_gran_reg = SHAPING_Q_GRAN_QLAYER_MIN0r; 1662 max_gran_reg = SHAPING_Q_GRAN_QLAYER_MAX0r; 1663 gran_shift = cosq; 1664 } else { 1665 min_gran_reg = SHAPING_Q_GRAN_QLAYER_MIN1r; 1666 max_gran_reg = SHAPING_Q_GRAN_QLAYER_MAX1r; 1667 gran_shift = cosq - 32; 1668 } 1669 eav_bucket_reg = EAVBUCKETCONFIG_EXT_QLAYERr; 1670 } else { 1671 min_gran_reg = SHAPING_Q_GRANr; 1672 max_gran_reg = SHAPING_Q_GRANr; 1673 gran_shift = cosq; 1674 eav_bucket_reg = EAVBUCKETCONFIG_EXTr; 1675 } 1676 } 1677 1678 if (node) { 1679 if (node->node_level == GH2_COSQ_LEVEL_QGROUP) { 1680 /* 1681 * Get the hw index of MMU_MAX/MIN_BUCKET_QGROUP table by 1682 * (port, cosq) 1683 */ 1684 BCM_IF_ERROR_RETURN( 1685 soc_gh2_mmu_bucket_qgroup_index(unit, 1686 local_port, 1687 cosq, 1688 &memidx)); 1689 } else { 1690 /* node->node_level is GH2_COSQ_LEVEL_QLAYER */ 1691 /* 1692 * Get the hw index of MMU_MAX/MIN_BUCKET_QLAYER table by 1693 * (port, cosq) 1694 */ 1695 BCM_IF_ERROR_RETURN( 1696 soc_gh2_mmu_bucket_qlayer_index(unit, 1697 local_port, 1698 node->qlayer_cosq_min + cosq, 1699 &memidx)); 1700 } 1701 } else { 1702 /* Get the index of MMU_MAX/MIN_BUCKET_QLAYER table by (port, cosq) */ 1703 BCM_IF_ERROR_RETURN(soc_gh2_mmu_bucket_qlayer_index 1704 (unit, local_port, cosq, &memidx)); 1705 } 1706 1707 if (!kbits_sec_min || !kbits_sec_max || !kbits_sec_burst || !flags) { 1708 return (BCM_E_PARAM); 1709 } 1710 1711 *flags = 0; 1712 1713 meter_flags |= _BCM_XGS_METER_FLAG_GRANULARITY; 1714 granularity = 3; /* reset to default */ 1715 1716 config_reg = max_gran_reg; 1717 shift = gran_shift; 1718 1719 BCM_IF_ERROR_RETURN 1720 (soc_reg32_get(unit, config_reg, local_port, 0, ®val)); 1721 if (soc_reg_field_valid(unit, config_reg, MAX_Q_GRANf)) { 1722 fval = soc_reg_field_get(unit, config_reg, 1723 regval, MAX_Q_GRANf); 1724 if (fval & (1 << shift)) { 1725 granularity = 5; 1726 } 1727 } 1728 1729 config_mem = max_bucket_mem; /* MMU_MAX_BUCKET_QLAYERm; */ 1730 BCM_IF_ERROR_RETURN 1731 (soc_mem_read(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry)); 1732 refresh_rate = soc_mem_field32_get(unit, config_mem, 1733 &entry, REFRESHf); 1734 bucketsize = soc_mem_field32_get(unit, config_mem, 1735 &entry, THD_SELf); 1736 eav_mode = soc_mem_field32_get(unit, config_mem, 1737 &entry, EAV_MODEf); 1738 BCM_IF_ERROR_RETURN 1739 (_bcm_xgs_bucket_encoding_to_kbits(refresh_rate, bucketsize, 1740 granularity, meter_flags, 1741 kbits_sec_max, kbits_sec_burst)); 1742 if ((eav_mode == 1) || (eav_mode == 2)) { 1743 *flags |= (eav_mode == 1) ? BCM_COSQ_BW_EAV_MODE : 1744 BCM_COSQ_BW_EAV_TAS_MODE; 1745 1746 config_reg = eav_bucket_reg; 1747 1748 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, config_reg, 1749 local_port, cosq, &rval)); 1750 bucket_lo = soc_reg_field_get(unit, config_reg, 1751 rval, EAV_THD_SEL_6LSBf); 1752 if (granularity == 5) { 1753 eav_gran = GH2_BURST_GRANULARITY_128B; 1754 } else { 1755 eav_gran = GH2_BURST_GRANULARITY_DEFAULT; 1756 } 1757 *kbits_sec_burst = (((bucketsize << 6) | bucket_lo) * 1758 eav_gran * 8) / 1000; 1759 } 1760 config_reg = eav_bucket_reg; 1761 if (SOC_REG_FIELD_VALID(unit, config_reg, GATE_CLOSE_FREEZE_MODEf)) { 1762 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, config_reg, 1763 local_port, cosq, &rval)); 1764 if (soc_reg_field_get(unit, config_reg, 1765 rval, GATE_CLOSE_FREEZE_MODEf)) { 1766 *flags |= BCM_COSQ_BW_TAS_TOKEN_FREEZE; 1767 } 1768 } 1769 1770 config_mem = min_bucket_mem; /* MMU_MIN_BUCKET_QLAYERm; */ 1771 BCM_IF_ERROR_RETURN 1772 (soc_mem_read(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry)); 1773 refresh_rate = soc_mem_field32_get(unit, config_mem, 1774 &entry, REFRESHf); 1775 1776 meter_flags = 0; /* reset to default */ 1777 granularity = 3; /* reset to default */ 1778 meter_flags |= _BCM_XGS_METER_FLAG_GRANULARITY; 1779 1780 config_reg = min_gran_reg; 1781 shift = gran_shift; 1782 1783 BCM_IF_ERROR_RETURN 1784 (soc_reg32_get(unit, config_reg, local_port, 0, ®val)); 1785 if (soc_reg_field_valid(unit, config_reg, MIN_Q_GRANf)) { 1786 fval = soc_reg_field_get(unit, config_reg, 1787 regval, MIN_Q_GRANf); 1788 if (fval & (1 << shift)) { 1789 granularity = 5; 1790 } 1791 } 1792 1793 BCM_IF_ERROR_RETURN 1794 (_bcm_xgs_bucket_encoding_to_kbits(refresh_rate, 0, 1795 granularity, meter_flags, 1796 kbits_sec_min, &kbits_min_burst)); 1797 1798 1799 return BCM_E_NONE; 1800 } 1801 1802 /* 1803 * Function: 1804 * bcmi_gh2_cosq_sched_weight_max_get 1805 * Purpose: 1806 * Retrieve maximum weights for given COS policy. 1807 * Parameters: 1808 * unit - StrataSwitch unit number. 1809 * mode - Scheduling mode, one of BCM_COSQ_xxx 1810 * weight_max - (output) Maximum weight for COS queue. 1811 * For DRR mode Weight is specified in Kbytes 1812 * 0 if mode is BCM_COSQ_STRICT. 1813 * 1 if mode is BCM_COSQ_ROUND_ROBIN. 1814 * -1 if not applicable to mode. 1815 * Returns: 1816 * BCM_E_XXX 1817 */ 1818 1819 int 1820 bcmi_gh2_cosq_sched_weight_max_get(int unit, int mode, int *weight_max) 1821 { 1822 switch (mode) { 1823 case BCM_COSQ_STRICT: 1824 *weight_max = BCM_COSQ_WEIGHT_STRICT; 1825 break; 1826 case BCM_COSQ_ROUND_ROBIN: 1827 *weight_max = BCM_COSQ_WEIGHT_MIN; 1828 break; 1829 case BCM_COSQ_WEIGHTED_ROUND_ROBIN: 1830 *weight_max = GH2_WRR_WEIGHT_MAX; 1831 break; 1832 case BCM_COSQ_DEFICIT_ROUND_ROBIN: 1833 /* max weight in kb will be 1834 max weight * max value of MTU quanta sel */ 1835 *weight_max = GH2_DRR_WEIGHT_MAX * \ 1836 MTU_GH2_Quanta[GH2_MTU_QUANTA_ID_COUNT - 1]; 1837 break; 1838 default: 1839 *weight_max = BCM_COSQ_WEIGHT_UNLIMITED; 1840 return BCM_E_PARAM; 1841 } 1842 1843 return BCM_E_NONE; 1844 } 1845 1846 /* Function: 1847 * bcmi_gh2_cos_max_weight 1848 * Purpose: 1849 * Get the max weight from the input weights. 1850 * Parameters: 1851 * weight - array of weight value. 1852 * Returns: 1853 * BCM_E_XXX 1854 */ 1855 static int 1856 bcmi_gh2_cos_max_weight(const int weight[]) 1857 { 1858 int i, max_weight = 0; 1859 1860 /* find max weight */ 1861 for (i = 0; i < 8; i++) { 1862 if (max_weight < weight[i]) { 1863 max_weight = weight[i]; 1864 } 1865 } 1866 return max_weight; 1867 } 1868 1869 /* 1870 * Calculates the Quanta needed for COS according to its weight 1871 */ 1872 static int 1873 bcmi_gh2_cos_drr_weights_to_quanta(const int weight[]) 1874 { 1875 int i, max_weight = 0; 1876 1877 max_weight = bcmi_gh2_cos_max_weight(weight); 1878 1879 for (i = 0; i < GH2_MTU_QUANTA_ID_COUNT; i++) { 1880 if (max_weight <= MTU_GH2_Quanta[i] * GH2_COS_WEIGHT_MAX) { 1881 return i; /* Right Quanta was found */ 1882 } 1883 } 1884 return -1; /* In case of too big weight return negative value */ 1885 } 1886 1887 /* 1888 * Convert the encoded weights to number of kbytes that can transmtted 1889 * in one run. 1890 */ 1891 static int 1892 bcmi_gh2_mtu_cos_drr_weight_to_kbytes(int weight, int MTUQuantaSel) 1893 { 1894 return (weight * MTU_GH2_Quanta[MTUQuantaSel]); 1895 } 1896 1897 /* 1898 * Convert the number of kbytes (1024 bytes) that can transmtted in one run 1899 * to weight encoding 1900 */ 1901 static int 1902 bcmi_gh2_mtu_cos_drr_kbytes_to_weight(int kbytes, int MTUQuantaSel) 1903 { 1904 int cos_weight = 0; 1905 int weight_found = FALSE, low_weight_boundary, hi_weight_boundary; 1906 1907 /* Search for right weight */ 1908 low_weight_boundary = 1; 1909 hi_weight_boundary = GH2_COS_WEIGHT_MAX; 1910 1911 /* Boundary conditions */ 1912 if (kbytes >= hi_weight_boundary * MTU_GH2_Quanta[MTUQuantaSel]) { 1913 cos_weight = hi_weight_boundary; 1914 weight_found = TRUE; 1915 } 1916 if (kbytes <= low_weight_boundary * MTU_GH2_Quanta[MTUQuantaSel]) { 1917 cos_weight = low_weight_boundary; 1918 weight_found = TRUE; 1919 } 1920 while (!weight_found) { 1921 cos_weight = (hi_weight_boundary + low_weight_boundary) / 2; 1922 if (kbytes <= cos_weight * MTU_GH2_Quanta[MTUQuantaSel]) { 1923 if (kbytes > ((cos_weight - 1) * MTU_GH2_Quanta[MTUQuantaSel])) { 1924 weight_found = TRUE; 1925 } else { 1926 hi_weight_boundary = cos_weight; 1927 } 1928 } else { 1929 if (kbytes <= ((cos_weight + 1) * MTU_GH2_Quanta[MTUQuantaSel])) { 1930 cos_weight++; 1931 weight_found = TRUE; 1932 } else { 1933 low_weight_boundary = cos_weight; 1934 } 1935 } 1936 } /* Here weight should be found */ 1937 return cos_weight; 1938 } 1939 1940 /* 1941 * Function: 1942 * bcmi_gh2_cosq_port_sched_set 1943 * Purpose: 1944 * Set class-of-service policy and corresponding weights and delay 1945 * Parameters: 1946 * unit - StrataSwitch unit number. 1947 * pbm - port bitmap 1948 * mode - (IN) Scheduling mode, one of BCM_COSQ_xxx 1949 * weights - (IN) Weights for each COS queue 1950 * Only for BCM_COSQ_WEIGHTED_ROUND_ROBIN and 1951 * BCM_COSQ_DEFICIT_ROUND_ROBIN mode. 1952 * For DRR Weight is specified in Kbytes 1953 * delay - This parameter is not used 1954 * Returns: 1955 * BCM_E_XXX 1956 */ 1957 int 1958 bcmi_gh2_cosq_port_sched_set(int unit, bcm_pbmp_t pbm, 1959 int mode, const int weights[], int delay) 1960 { 1961 uint32 wrr; 1962 int port; 1963 uint32 cosarbsel; 1964 int mbits = 0; 1965 int i, max_weight; 1966 int enc_weights[8]; 1967 int MTUQuantaSel = 0; 1968 soc_reg_t config_reg = INVALIDr; 1969 int is_64q_port; 1970 1971 COMPILER_REFERENCE(delay); 1972 mbcm_driver[unit]->mbcm_cosq_sched_weight_max_get(unit, mode, &max_weight); 1973 if ((mode != BCM_COSQ_STRICT) && (mode != BCM_COSQ_ROUND_ROBIN) && 1974 (max_weight != BCM_COSQ_WEIGHT_UNLIMITED)) { 1975 for (i = 0; i < NUM_COS(unit); i++) { 1976 if ((weights[i] < 0) || (weights[i] > max_weight)) { 1977 return BCM_E_PARAM; 1978 } 1979 } 1980 } 1981 1982 /* Initialize all weights 0 (Strict Priority). */ 1983 for (i = 0; i < 8; i++) { 1984 enc_weights[i] = 0; 1985 } 1986 1987 switch (mode) { 1988 case BCM_COSQ_STRICT: 1989 mbits = 0; 1990 break; 1991 case BCM_COSQ_ROUND_ROBIN: 1992 mbits = 1; 1993 break; 1994 case BCM_COSQ_WEIGHTED_ROUND_ROBIN: 1995 mbits = 2; 1996 /* 1997 * All weight values must fit within 7 bits. 1998 * If weight is 0, this queue is run in strict mode, 1999 * others run in WRR mode. 2000 */ 2001 2002 for (i = 0; i < NUM_COS(unit); i++) { 2003 enc_weights[i] = weights[i]; 2004 } 2005 break; 2006 case BCM_COSQ_DEFICIT_ROUND_ROBIN: 2007 mbits = 3; 2008 if (soc_feature(unit, soc_feature_linear_drr_weight)) { 2009 MTUQuantaSel = bcmi_gh2_cos_drr_weights_to_quanta(weights); 2010 if (MTUQuantaSel < 0) { 2011 return BCM_E_PARAM; 2012 } 2013 for (i = 0; i < NUM_COS(unit); i++) { 2014 if (weights[i]) { 2015 enc_weights[i] = 2016 bcmi_gh2_mtu_cos_drr_kbytes_to_weight(weights[i], 2017 MTUQuantaSel); 2018 } else { 2019 enc_weights[i] = weights[i]; 2020 } 2021 } 2022 } /* soc_feature_linear_drr_weight */ 2023 break; 2024 case BCM_COSQ_BOUNDED_DELAY: /* not supported in xgs */ 2025 default: 2026 return BCM_E_PARAM; 2027 } 2028 2029 PBMP_ITER(pbm, port) { 2030 cosarbsel = 0; 2031 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, port, &is_64q_port)); 2032 2033 if (is_64q_port) { 2034 config_reg = XQCOSARBSEL_QLAYERr; 2035 } else { 2036 config_reg = XQCOSARBSELr; 2037 } 2038 soc_reg_field_set(unit, config_reg, &cosarbsel, COSARBf, mbits); 2039 if ((mode == BCM_COSQ_DEFICIT_ROUND_ROBIN) && 2040 (soc_feature(unit, soc_feature_linear_drr_weight))) { 2041 soc_reg_field_set(unit, config_reg, &cosarbsel, 2042 MTU_QUANTA_SELECTf, MTUQuantaSel); 2043 } 2044 BCM_IF_ERROR_RETURN 2045 (soc_reg32_set(unit, config_reg, port, 0, cosarbsel)); 2046 } 2047 2048 if ((mode == BCM_COSQ_WEIGHTED_ROUND_ROBIN) || 2049 (mode == BCM_COSQ_DEFICIT_ROUND_ROBIN)) { 2050 /* 2051 * Weighted Fair Queueing scheduling among vaild COSs 2052 */ 2053 PBMP_ITER(pbm, port) { 2054 if (soc_feature(unit, soc_feature_linear_drr_weight)) { 2055 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, port, 2056 &is_64q_port)); 2057 if (is_64q_port) { 2058 config_reg = WRRWEIGHT_COS_QLAYERr; 2059 } else { 2060 config_reg = WRRWEIGHT_COSr; 2061 } 2062 for (i = 0; i < NUM_COS(unit); i++) { 2063 BCM_IF_ERROR_RETURN 2064 (soc_reg32_get(unit, config_reg, port, i, &wrr)); 2065 soc_reg_field_set(unit, config_reg, &wrr, 2066 WEIGHTf, enc_weights[i]); 2067 BCM_IF_ERROR_RETURN 2068 (soc_reg32_set(unit, config_reg, port, i, wrr)); 2069 } 2070 } 2071 } 2072 } 2073 2074 return BCM_E_NONE; 2075 } 2076 2077 /* 2078 * Function: 2079 * bcmi_gh2_cosq_port_sched_get 2080 * Purpose: 2081 * Retrieve class-of-service policy and corresponding weights and delay 2082 * Parameters: 2083 * unit - StrataSwitch unit number. 2084 * pbm - port bitmap 2085 * mode - (output) Scheduling mode, one of BCM_COSQ_xxx 2086 * weights - (output) Weights for each COS queue 2087 * Only for BCM_COSQ_WEIGHTED_ROUND_ROBIN and 2088 * BCM_COSQ_DEFICIT_ROUND_ROBIN mode. 2089 * For DRR Weight is specified in Kbytes 2090 * delay - This parameter is not used 2091 * Returns: 2092 * BCM_E_XXX 2093 * Notes: 2094 * Actually just returns data for the first port in the bitmap 2095 */ 2096 2097 int 2098 bcmi_gh2_cosq_port_sched_get(int unit, bcm_pbmp_t pbm, 2099 int *mode, int weights[], int *delay) 2100 { 2101 uint32 cosarbsel, wrr; 2102 int mbits, port, i; 2103 int MTUQuantaSel = -1; 2104 soc_reg_t config_reg = INVALIDr; 2105 int is_64q_port; 2106 2107 mbits = -1; 2108 PBMP_ITER(pbm, port) { 2109 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, port, &is_64q_port)); 2110 2111 if (is_64q_port) { 2112 config_reg = XQCOSARBSEL_QLAYERr; 2113 } else { 2114 config_reg = XQCOSARBSELr; 2115 } 2116 2117 BCM_IF_ERROR_RETURN 2118 (soc_reg32_get(unit, config_reg, port, 0, &cosarbsel)); 2119 mbits = soc_reg_field_get(unit, config_reg, cosarbsel, COSARBf); 2120 if (soc_feature(unit, soc_feature_linear_drr_weight)) { 2121 MTUQuantaSel = 2122 soc_reg_field_get(unit, config_reg, cosarbsel, 2123 MTU_QUANTA_SELECTf); 2124 } 2125 break; 2126 } 2127 switch (mbits) { 2128 case 0: 2129 *mode = BCM_COSQ_STRICT; 2130 break; 2131 case 1: 2132 *mode = BCM_COSQ_ROUND_ROBIN; 2133 break; 2134 case 2: 2135 *mode = BCM_COSQ_WEIGHTED_ROUND_ROBIN; 2136 break; 2137 case 3: 2138 *mode = BCM_COSQ_DEFICIT_ROUND_ROBIN; 2139 break; 2140 default: 2141 return BCM_E_INTERNAL; 2142 } 2143 if ((mbits == 2) || (mbits == 3)) { 2144 wrr = 0; 2145 if (soc_feature(unit, soc_feature_linear_drr_weight)) { 2146 PBMP_ITER(pbm, port) { 2147 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, port, 2148 &is_64q_port)); 2149 if (is_64q_port) { 2150 config_reg = WRRWEIGHT_COS_QLAYERr; 2151 } else { 2152 config_reg = WRRWEIGHT_COSr; 2153 } 2154 2155 2156 for (i = 0; i < NUM_COS(unit); i++) { 2157 BCM_IF_ERROR_RETURN 2158 (soc_reg32_get(unit, config_reg, port, i, &wrr)); 2159 weights[i] = soc_reg_field_get(unit, config_reg, 2160 wrr, WEIGHTf); 2161 } 2162 } 2163 } 2164 if (mbits == 3) { 2165 int i; 2166 for (i = 0; i < NUM_COS(unit); i++) { 2167 if (soc_feature(unit, soc_feature_linear_drr_weight)) { 2168 weights[i] = 2169 bcmi_gh2_mtu_cos_drr_weight_to_kbytes( 2170 weights[i], MTUQuantaSel); 2171 } 2172 } 2173 } 2174 } 2175 if (delay) { 2176 *delay = 0; 2177 } 2178 return BCM_E_NONE; 2179 } 2180 2181 /* 2182 * Function: 2183 * bcmi_gh2_cosq_mapping_set 2184 * Purpose: 2185 * Set which cosq a given priority should fall into 2186 * Parameters: 2187 * unit - StrataSwitch unit number. 2188 * priority - Priority value to map 2189 * cosq - COS queue to map to 2190 * Returns: 2191 * BCM_E_XXX 2192 */ 2193 2194 int 2195 bcmi_gh2_cosq_mapping_set(int unit, bcm_port_t port, 2196 bcm_cos_t priority, bcm_cos_queue_t cosq) 2197 { 2198 uint32 val, old_index, new_index; 2199 int i; 2200 port_cos_map_entry_t cos_map_array[GH2_COS_MAP_ENTRIES_PER_SET], *entry_p; 2201 void *entries[GH2_COS_MAP_ENTRIES_PER_SET]; 2202 bcm_pbmp_t ports; 2203 bcm_port_t local_port; 2204 2205 if (priority < 0 || priority >= 16) { 2206 return (BCM_E_PARAM); 2207 } 2208 2209 if (cosq < 0 || cosq >= 8) { 2210 return (BCM_E_PARAM); 2211 } 2212 2213 if (port == -1) { /* all ports */ 2214 BCM_PBMP_ASSIGN(ports, PBMP_ALL(unit)); 2215 } else { 2216 if (BCM_GPORT_IS_SET(port)) { 2217 BCM_IF_ERROR_RETURN( 2218 bcm_esw_port_local_get(unit, port, &local_port)); 2219 } else { 2220 local_port = port; 2221 } 2222 2223 if (!SOC_PORT_VALID(unit, local_port) || \ 2224 !IS_ALL_PORT(unit, local_port)) { 2225 return BCM_E_PORT; 2226 } 2227 BCM_PBMP_CLEAR(ports); 2228 BCM_PBMP_PORT_ADD(ports, local_port); 2229 } 2230 2231 PBMP_ITER(ports, local_port) { 2232 SOC_IF_ERROR_RETURN(READ_COS_MAP_SELr(unit, local_port, &val)); 2233 old_index = soc_reg_field_get(unit, COS_MAP_SELr, val, SELECTf); 2234 old_index *= GH2_COS_MAP_ENTRIES_PER_SET; 2235 2236 /* get current mapping profile values */ 2237 for (i = 0; i < GH2_COS_MAP_ENTRIES_PER_SET; i++) { 2238 entry_p = SOC_PROFILE_MEM_ENTRY(unit, gh2_cos_map_profile[unit], 2239 port_cos_map_entry_t *, 2240 (old_index + i)); 2241 memcpy(&cos_map_array[i], entry_p, sizeof(*entry_p)); 2242 entries[i] = (void *) &cos_map_array[i]; 2243 } 2244 soc_mem_field32_set(unit, PORT_COS_MAPm, 2245 &cos_map_array[priority], COSf, cosq); 2246 SOC_IF_ERROR_RETURN 2247 (soc_profile_mem_add(unit, gh2_cos_map_profile[unit], 2248 (void *) &entries, 2249 GH2_COS_MAP_ENTRIES_PER_SET, &new_index)); 2250 SOC_IF_ERROR_RETURN 2251 (soc_reg_field32_modify(unit, COS_MAP_SELr, local_port, 2252 SELECTf, 2253 new_index / GH2_COS_MAP_ENTRIES_PER_SET)); 2254 SOC_IF_ERROR_RETURN 2255 (soc_profile_mem_delete(unit, 2256 gh2_cos_map_profile[unit], old_index)); 2257 2258 #ifndef BCM_COSQ_HIGIG_MAP_DISABLE 2259 if (IS_HG_PORT(unit, local_port) || local_port == CMIC_PORT(unit)) { 2260 SOC_IF_ERROR_RETURN 2261 (soc_profile_mem_add(unit, gh2_cos_map_profile[unit], 2262 (void *) &entries, 2263 GH2_COS_MAP_ENTRIES_PER_SET, &new_index)); 2264 SOC_IF_ERROR_RETURN 2265 (soc_reg_field32_modify(unit, ICOS_MAP_SELr, local_port, 2266 SELECTf, 2267 new_index / GH2_COS_MAP_ENTRIES_PER_SET) 2268 ); 2269 SOC_IF_ERROR_RETURN 2270 (soc_profile_mem_delete(unit, 2271 gh2_cos_map_profile[unit], old_index)); 2272 } 2273 #endif 2274 } 2275 return BCM_E_NONE; 2276 } 2277 2278 /* 2279 * Function: 2280 * bcmi_gh2_cosq_mapping_get 2281 * Purpose: 2282 * Determine which COS queue a given priority currently maps to. 2283 * Parameters: 2284 * unit - StrataSwitch unit number. 2285 * priority - Priority value 2286 * cosq - (Output) COS queue number 2287 * Returns: 2288 * BCM_E_XXX 2289 */ 2290 2291 int 2292 bcmi_gh2_cosq_mapping_get(int unit, bcm_port_t port, 2293 bcm_cos_t priority, bcm_cos_queue_t *cosq) 2294 { 2295 uint32 val; 2296 int index; 2297 port_cos_map_entry_t *entry_p; 2298 bcm_port_t local_port; 2299 2300 if (priority < 0 || priority >= 16) { 2301 return (BCM_E_PARAM); 2302 } 2303 2304 if (port == -1) { 2305 local_port = REG_PORT_ANY; 2306 } else { 2307 if (BCM_GPORT_IS_SET(port)) { 2308 BCM_IF_ERROR_RETURN( 2309 bcm_esw_port_local_get(unit, port, &local_port)); 2310 } else { 2311 local_port = port; 2312 } 2313 2314 if (!SOC_PORT_VALID(unit, local_port) || \ 2315 !IS_ALL_PORT(unit, local_port)) { 2316 return BCM_E_PORT; 2317 } 2318 } 2319 2320 SOC_IF_ERROR_RETURN(READ_COS_MAP_SELr(unit, local_port, &val)); 2321 index = soc_reg_field_get(unit, COS_MAP_SELr, val, SELECTf); 2322 index *= GH2_COS_MAP_ENTRIES_PER_SET; 2323 2324 entry_p = SOC_PROFILE_MEM_ENTRY(unit, gh2_cos_map_profile[unit], 2325 port_cos_map_entry_t *, 2326 (index + priority)); 2327 *cosq = soc_mem_field32_get(unit, PORT_COS_MAPm, entry_p, COSf); 2328 return BCM_E_NONE; 2329 } 2330 2331 2332 /* 2333 * Function: 2334 * bcmi_gh2_cosq_gport_bandwidth_set 2335 * Purpose: 2336 * 2337 * Parameters: 2338 * unit - (IN) Unit number. 2339 * gport - (IN) GPORT ID. 2340 * cosq - (IN) COS queue to configure, -1 for all COS queues. 2341 * kbits_sec_min - (IN) minimum bandwidth, kbits/sec. 2342 * kbits_sec_max - (IN) maximum bandwidth, kbits/sec. 2343 * flags - (IN) BCM_COSQ_BW_* 2344 * Returns: 2345 * BCM_E_XXX 2346 */ 2347 int 2348 bcmi_gh2_cosq_gport_bandwidth_set(int unit, bcm_gport_t gport, 2349 bcm_cos_queue_t cosq, uint32 kbits_sec_min, 2350 uint32 kbits_sec_max, uint32 flags) 2351 { 2352 bcm_port_t local_port; 2353 int i; 2354 bcm_cos_queue_t cosq_start = 0, cosq_end = 0; 2355 2356 BCM_IF_ERROR_RETURN 2357 (bcmi_gh2_cosq_gport_bandwidth_port_resolve(unit, gport, cosq, 2358 &local_port, 2359 &cosq_start, &cosq_end)); 2360 2361 for (i = cosq_start; i <= cosq_end; i++) { 2362 BCM_IF_ERROR_RETURN 2363 (bcmi_gh2_cosq_port_bandwidth_set(unit, gport, i, 2364 kbits_sec_min, 2365 kbits_sec_max, 2366 kbits_sec_max, 2367 flags)); 2368 } 2369 2370 return BCM_E_NONE; 2371 } 2372 2373 /* 2374 * Function: 2375 * bcmi_gh2_cosq_gport_bandwidth_get 2376 * Purpose: 2377 * 2378 * Parameters: 2379 * unit - (IN) Unit number. 2380 * gport - (IN) GPORT ID. 2381 * cosq - (IN) COS queue to configure, -1 for all COS queues. 2382 * kbits_sec_min - (OUT) minimum bandwidth, kbits/sec. 2383 * kbits_sec_max - (OUT) maximum bandwidth, kbits/sec. 2384 * flags - (OUT) BCM_COSQ_BW_* 2385 * Returns: 2386 * BCM_E_XXX 2387 */ 2388 int 2389 bcmi_gh2_cosq_gport_bandwidth_get(int unit, bcm_gport_t gport, 2390 bcm_cos_queue_t cosq, uint32 *kbits_sec_min, 2391 uint32 *kbits_sec_max, uint32 *flags) 2392 { 2393 bcm_port_t local_port; 2394 bcm_cos_queue_t cosq_start = 0, cosq_end = 0; 2395 uint32 kbits_sec_burst; /* Dummy variable */ 2396 2397 *kbits_sec_min = *kbits_sec_max = *flags = 0; 2398 2399 BCM_IF_ERROR_RETURN 2400 (bcmi_gh2_cosq_gport_bandwidth_port_resolve(unit, gport, cosq, 2401 &local_port, 2402 &cosq_start, &cosq_end)); 2403 BCM_IF_ERROR_RETURN 2404 (bcmi_gh2_cosq_port_bandwidth_get(unit, gport, cosq_start, 2405 kbits_sec_min, kbits_sec_max, 2406 &kbits_sec_burst, flags)); 2407 return BCM_E_NONE; 2408 } 2409 2410 /* 2411 * Convert the number of kbytes (1024 bytes) that can transmtted in one run 2412 * to weight encoding for 2413 */ 2414 static int 2415 bcmi_gh2_cos_drr_kbytes_to_weight(int kbytes, int MTUQuantaSel) 2416 { 2417 int cos_weight = 0; 2418 int weight_found = FALSE, low_weight_boundary, hi_weight_boundary; 2419 2420 /* Search for right weight */ 2421 low_weight_boundary = 1; 2422 hi_weight_boundary = GH2_COS_WEIGHT_MAX; 2423 2424 /* Boundary conditions */ 2425 if (kbytes >= hi_weight_boundary * MTU_GH2_Quanta[MTUQuantaSel]) { 2426 cos_weight = hi_weight_boundary; 2427 weight_found = TRUE; 2428 } 2429 if (kbytes <= low_weight_boundary * MTU_GH2_Quanta[MTUQuantaSel]) { 2430 cos_weight = low_weight_boundary; 2431 weight_found = TRUE; 2432 } 2433 2434 while (!weight_found) { 2435 cos_weight = (hi_weight_boundary + low_weight_boundary) / 2; 2436 if (kbytes <= cos_weight * MTU_GH2_Quanta[MTUQuantaSel]) { 2437 if (kbytes > ((cos_weight - 1) * MTU_GH2_Quanta[MTUQuantaSel])) { 2438 weight_found = TRUE; 2439 } else { 2440 hi_weight_boundary = cos_weight; 2441 } 2442 } else { 2443 if (kbytes <= ((cos_weight + 1) * MTU_GH2_Quanta[MTUQuantaSel])) { 2444 cos_weight++; 2445 weight_found = TRUE; 2446 } else { 2447 low_weight_boundary = cos_weight; 2448 } 2449 } 2450 } /* Here weight should be found */ 2451 2452 return cos_weight; 2453 } 2454 2455 /* 2456 * Function: 2457 * bcmi_gh2_cosq_port_schedule_set 2458 * Purpose: 2459 * Set scheduling mode 2460 * Parameters: 2461 * unit - (IN) unit number 2462 * config_reg - (IN) register for configuration mode 2463 * weight_reg - (IN) register for configuratin weight 2464 * port - (IN) port number or GPORT identifier 2465 * qlayer_sch_id - (IN) scheduler id 2466 * start_cosq - (IN) COS queue number 2467 * num_weights - (IN) number of entries in weights array 2468 * weights - (IN) weights array 2469 * mode - (IN) scheduling mode (BCM_COSQ_XXX) 2470 * Returns: 2471 * BCM_E_XXX 2472 */ 2473 STATIC int 2474 bcmi_gh2_cosq_port_schedule_set(int unit, soc_reg_t config_reg, 2475 soc_reg_t weight_reg, bcm_port_t port, 2476 int qlayer_sch_id, 2477 bcm_cos_queue_t start_cosq, 2478 int num_weights, const int weights[], 2479 int mode) 2480 { 2481 int t, i, cosq; 2482 uint32 wrr; 2483 uint32 reg_val; 2484 int mbits = 0; 2485 int enc_weights[8]; 2486 int MTUQuantaSel = 0; 2487 2488 switch (mode) { 2489 case BCM_COSQ_STRICT: 2490 mbits = 0; 2491 break; 2492 case BCM_COSQ_ROUND_ROBIN: 2493 mbits = 1; 2494 break; 2495 case BCM_COSQ_WEIGHTED_ROUND_ROBIN: 2496 mbits = 2; 2497 /* 2498 * All weight values must fit within 7 bits. 2499 * If weight is 0, this queue is run in strict mode, 2500 * others run in WRR mode. 2501 */ 2502 t = 0; 2503 for (i = 0; i < num_weights; i++) { 2504 t |= weights[i]; 2505 } 2506 if ((t & ~0x7f) != 0) { 2507 return BCM_E_PARAM; 2508 } 2509 for (i = 0; i < num_weights; i++) { 2510 enc_weights[i] = weights[i]; 2511 } 2512 break; 2513 case BCM_COSQ_DEFICIT_ROUND_ROBIN: 2514 mbits = 3; 2515 MTUQuantaSel = bcmi_gh2_cos_drr_weights_to_quanta(weights); 2516 if (MTUQuantaSel < 0) { 2517 return BCM_E_PARAM; 2518 } 2519 2520 for (i = 0; i < num_weights; i++) { 2521 if (weights[i]) { 2522 enc_weights[i] = 2523 bcmi_gh2_cos_drr_kbytes_to_weight(weights[i], 2524 MTUQuantaSel); 2525 } else { 2526 enc_weights[i] = weights[i]; 2527 } 2528 2529 } 2530 break; 2531 case BCM_COSQ_BOUNDED_DELAY: /* not supported in xgs */ 2532 default: 2533 return BCM_E_PARAM; 2534 } 2535 2536 /* Program the scheduling mode */ 2537 BCM_IF_ERROR_RETURN 2538 (soc_reg32_get(unit, config_reg, port, qlayer_sch_id, ®_val)); 2539 soc_reg_field_set(unit, config_reg, ®_val, COSARBf, mbits); 2540 if ((mode == BCM_COSQ_DEFICIT_ROUND_ROBIN) && 2541 (soc_feature(unit, soc_feature_linear_drr_weight))) { 2542 soc_reg_field_set(unit, config_reg, ®_val, 2543 MTU_QUANTA_SELECTf, MTUQuantaSel); 2544 } 2545 BCM_IF_ERROR_RETURN 2546 (soc_reg32_set(unit, config_reg, port, qlayer_sch_id, reg_val)); 2547 2548 if ((mode == BCM_COSQ_WEIGHTED_ROUND_ROBIN) || 2549 (mode == BCM_COSQ_DEFICIT_ROUND_ROBIN)) { 2550 /* 2551 * Weighted Fair Queueing scheduling among vaild COSs 2552 */ 2553 for (cosq = start_cosq, i = 0; i < num_weights; cosq++, i++) { 2554 BCM_IF_ERROR_RETURN 2555 (soc_reg32_get(unit, weight_reg, port, cosq, &wrr)); 2556 soc_reg_field_set(unit, weight_reg, &wrr, 2557 WEIGHTf, enc_weights[i]); 2558 BCM_IF_ERROR_RETURN 2559 (soc_reg32_set(unit, weight_reg, port, cosq, wrr)); 2560 } 2561 } 2562 return BCM_E_NONE; 2563 } 2564 2565 /* 2566 * Function: 2567 * bcmi_gh2_cosq_gport_sched_set 2568 * Purpose: 2569 * 2570 * Parameters: 2571 * unit - (IN) Unit number. 2572 * gport - (IN) GPORT ID. 2573 * cosq - (IN) COS queue to configure, -1 for all COS queues. 2574 * mode - (IN) Scheduling mode, one of BCM_COSQ_xxx 2575 * weight - (IN) Weight for the specified COS queue(s) 2576 * Unused if mode is BCM_COSQ_STRICT. 2577 * Returns: 2578 * BCM_E_XXX 2579 */ 2580 int 2581 bcmi_gh2_cosq_gport_sched_set(int unit, bcm_gport_t gport, 2582 bcm_cos_queue_t cosq, int mode, int weight) 2583 { 2584 bcm_port_t local_port; 2585 int i; 2586 gh2_cosq_node_t *node = NULL; 2587 int qlayer_sch_id = 0; 2588 bcm_cos_queue_t cosq_start = 0; 2589 int num_weights = 1, weights[8]; 2590 soc_reg_t config_reg = INVALIDr; 2591 soc_reg_t weight_reg = INVALIDr; 2592 int is_64q_port; 2593 2594 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 2595 /* scheduling is supported on scheduler node */ 2596 return BCM_E_PORT; 2597 } 2598 2599 sal_memset(&weights, 0, sizeof(int) * 8); 2600 2601 if (BCM_GPORT_IS_SCHEDULER(gport)) { 2602 BCM_IF_ERROR_RETURN 2603 (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL, 2604 &local_port, NULL, &node)); 2605 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port, 2606 &is_64q_port)); 2607 if (!is_64q_port) { 2608 return BCM_E_PORT; 2609 } 2610 2611 if (node->node_level == GH2_COSQ_LEVEL_QGROUP) { 2612 config_reg = XQCOSARBSEL_QGROUPr; 2613 weight_reg = WRRWEIGHT_COS_QGROUPr; 2614 } else { 2615 config_reg = XQCOSARBSEL_QLAYERr; 2616 weight_reg = WRRWEIGHT_COS_QLAYERr; 2617 qlayer_sch_id = node->child_idx; 2618 } 2619 } else { 2620 BCM_IF_ERROR_RETURN 2621 (bcmi_gh2_cosq_localport_resolve(unit, gport, &local_port)); 2622 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port, 2623 &is_64q_port)); 2624 2625 if (is_64q_port) { 2626 config_reg = XQCOSARBSEL_QLAYERr; 2627 weight_reg = WRRWEIGHT_COS_QLAYERr; 2628 } else { 2629 config_reg = XQCOSARBSELr; 2630 weight_reg = WRRWEIGHT_COSr; 2631 } 2632 } 2633 2634 if (cosq >= gh2_num_cosq[unit]) { 2635 return BCM_E_PARAM; 2636 } else if (cosq < 0) { 2637 if (node && (node->node_level == GH2_COSQ_LEVEL_QLAYER)) { 2638 cosq_start = node->qlayer_cosq_min; 2639 } else { 2640 cosq_start = 0; 2641 } 2642 num_weights = 8; 2643 for (i = 0; i < num_weights; i++) { 2644 if (i < gh2_num_cosq[unit]) { 2645 weights[i] = weight; 2646 } else { 2647 weights[i] = 0; 2648 } 2649 } 2650 } else { 2651 if (node && (node->node_level == GH2_COSQ_LEVEL_QLAYER)) { 2652 cosq_start = node->qlayer_cosq_min + cosq; 2653 } else { 2654 cosq_start = cosq; 2655 } 2656 num_weights = 1; 2657 weights[0] = weight; 2658 } 2659 BCM_IF_ERROR_RETURN 2660 (bcmi_gh2_cosq_port_schedule_set(unit, config_reg, weight_reg, 2661 local_port, qlayer_sch_id, 2662 cosq_start, num_weights, 2663 weights, mode)); 2664 return BCM_E_NONE; 2665 } 2666 2667 /* 2668 * Function: 2669 * bcmi_gh2_cosq_port_schedule_get 2670 * Purpose: 2671 * Set scheduling mode 2672 * Parameters: 2673 * unit - (IN) unit number 2674 * config_reg - (IN) register for configuration mode 2675 * weight_reg - (IN) register for configuratin weight 2676 * port - (IN) port number or GPORT identifier 2677 * qlayer_sch_id - (IN) scheduler id 2678 * start_cosq - (IN) COS queue number 2679 * num_weights - (IN) number of entries in weights array 2680 * weights - (IN) weights array 2681 * mode - (OUT) scheduling mode (BCM_COSQ_XXX) 2682 * Returns: 2683 * BCM_E_XXX 2684 */ 2685 STATIC int 2686 bcmi_gh2_cosq_port_schedule_get(int unit, soc_reg_t config_reg, 2687 soc_reg_t weight_reg, bcm_port_t port, 2688 int qlayer_sch_id, 2689 bcm_cos_queue_t start_cosq, 2690 int num_weights, int weights[], int *mode) 2691 { 2692 uint32 escfg, wrr; 2693 int mbits, i, cosq; 2694 int MTUQuantaSel = -1; 2695 2696 if (mode == NULL) { 2697 return BCM_E_PARAM; 2698 } 2699 2700 BCM_IF_ERROR_RETURN 2701 (soc_reg32_get(unit, config_reg, port, qlayer_sch_id, &escfg)); 2702 mbits = soc_reg_field_get(unit, config_reg, escfg, COSARBf); 2703 MTUQuantaSel = soc_reg_field_get(unit, config_reg, escfg, 2704 MTU_QUANTA_SELECTf); 2705 2706 switch (mbits) { 2707 case 0: 2708 *mode = BCM_COSQ_STRICT; 2709 break; 2710 case 1: 2711 *mode = BCM_COSQ_ROUND_ROBIN; 2712 break; 2713 case 2: 2714 *mode = BCM_COSQ_WEIGHTED_ROUND_ROBIN; 2715 break; 2716 case 3: 2717 *mode = BCM_COSQ_DEFICIT_ROUND_ROBIN; 2718 break; 2719 default: 2720 return BCM_E_INTERNAL; 2721 } 2722 2723 if ((mbits == 2) || (mbits == 3)) { 2724 wrr = 0; 2725 for (cosq = start_cosq, i = 0; i < num_weights; cosq++, i++) { 2726 BCM_IF_ERROR_RETURN 2727 (soc_reg32_get(unit, weight_reg, port, cosq, &wrr)); 2728 weights[i] = soc_reg_field_get(unit, weight_reg, wrr, 2729 WEIGHTf); 2730 } 2731 2732 if (mbits == 3) { 2733 int i; 2734 for (i = 0; i < num_weights; i++) { 2735 weights[i] = 2736 bcmi_gh2_mtu_cos_drr_weight_to_kbytes(weights[i], 2737 MTUQuantaSel); 2738 } 2739 } 2740 } 2741 return BCM_E_NONE; 2742 } 2743 2744 /* 2745 * Function: 2746 * bcmi_gh2_cosq_gport_sched_get 2747 * Purpose: 2748 * 2749 * Parameters: 2750 * unit - (IN) Unit number. 2751 * gport - (IN) GPORT ID. 2752 * cosq - (IN) COS queue 2753 * mode - (OUT) Scheduling mode, one of BCM_COSQ_xxx 2754 * weight - (OUT) Weight for the specified COS queue(s) 2755 * Unused if mode is BCM_COSQ_STRICT. 2756 * Returns: 2757 * BCM_E_XXX 2758 */ 2759 int 2760 bcmi_gh2_cosq_gport_sched_get(int unit, bcm_gport_t gport, 2761 bcm_cos_queue_t cosq, int *mode, int *weight) 2762 { 2763 bcm_port_t local_port; 2764 soc_reg_t config_reg = INVALIDr; 2765 soc_reg_t weight_reg = INVALIDr; 2766 int is_64q_port; 2767 gh2_cosq_node_t *node = NULL; 2768 int qlayer_sch_id = 0; 2769 bcm_cos_queue_t cosq_start = 0; 2770 2771 if ((mode == NULL) || (weight == NULL)) { 2772 return BCM_E_PARAM; 2773 } 2774 2775 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 2776 /* scheduling is supported on scheduler node */ 2777 return BCM_E_PORT; 2778 } 2779 2780 *mode = *weight = 0; 2781 2782 if (BCM_GPORT_IS_SCHEDULER(gport)) { 2783 BCM_IF_ERROR_RETURN 2784 (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL, 2785 &local_port, NULL, &node)); 2786 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port, 2787 &is_64q_port)); 2788 if (!is_64q_port) { 2789 return BCM_E_PORT; 2790 } 2791 2792 if (node->node_level == GH2_COSQ_LEVEL_QGROUP) { 2793 config_reg = XQCOSARBSEL_QGROUPr; 2794 weight_reg = WRRWEIGHT_COS_QGROUPr; 2795 } else { 2796 config_reg = XQCOSARBSEL_QLAYERr; 2797 weight_reg = WRRWEIGHT_COS_QLAYERr; 2798 qlayer_sch_id = node->child_idx; 2799 } 2800 } else { 2801 BCM_IF_ERROR_RETURN 2802 (bcmi_gh2_cosq_localport_resolve(unit, gport, &local_port)); 2803 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port, 2804 &is_64q_port)); 2805 2806 if (is_64q_port) { 2807 config_reg = XQCOSARBSEL_QLAYERr; 2808 weight_reg = WRRWEIGHT_COS_QLAYERr; 2809 } else { 2810 config_reg = XQCOSARBSELr; 2811 weight_reg = WRRWEIGHT_COSr; 2812 } 2813 } 2814 2815 if (cosq >= gh2_num_cosq[unit]) { 2816 return BCM_E_PARAM; 2817 } else if (cosq < 0) { 2818 cosq = 0; 2819 } 2820 2821 if (node && (node->node_level == GH2_COSQ_LEVEL_QLAYER)) { 2822 cosq_start = node->qlayer_cosq_min + cosq; 2823 } else { 2824 cosq_start = cosq; 2825 } 2826 2827 BCM_IF_ERROR_RETURN 2828 (bcmi_gh2_cosq_port_schedule_get(unit, config_reg, weight_reg, 2829 local_port, qlayer_sch_id, 2830 cosq_start, 1, 2831 weight, mode)); 2832 return BCM_E_NONE; 2833 } 2834 2835 /* 2836 * Function: 2837 * bcmi_gh2_cosq_gport_bandwidth_burst_set 2838 * Purpose: 2839 * 2840 * Parameters: 2841 * unit - (IN) Unit number. 2842 * gport - (IN) GPORT ID. 2843 * cosq - (IN) COS queue to configure, -1 for all COS queues. 2844 * kbits_burst - (IN) maximum burst, kbits. 2845 * Returns: 2846 * BCM_E_XXX 2847 */ 2848 int 2849 bcmi_gh2_cosq_gport_bandwidth_burst_set(int unit, bcm_gport_t gport, 2850 bcm_cos_queue_t cosq, 2851 uint32 kbits_burst) 2852 { 2853 bcm_port_t local_port, port; 2854 int i; 2855 bcm_cos_queue_t cosq_start = 0, cosq_end = 0; 2856 uint32 kbits_sec_min, kbits_sec_max, flags; 2857 uint32 kbits_sec_burst; /* Dummy variable */ 2858 2859 if (gport < 0) { 2860 PBMP_ALL_ITER(unit, port) { 2861 BCM_IF_ERROR_RETURN 2862 (bcmi_gh2_cosq_gport_bandwidth_port_resolve(unit, port, cosq, 2863 &local_port, 2864 &cosq_start, 2865 &cosq_end)); 2866 for (i = cosq_start; i <= cosq_end; i++) { 2867 BCM_IF_ERROR_RETURN 2868 (bcmi_gh2_cosq_port_bandwidth_get( 2869 unit, local_port, i, 2870 &kbits_sec_min, 2871 &kbits_sec_max, 2872 &kbits_sec_burst, &flags)); 2873 BCM_IF_ERROR_RETURN 2874 (bcmi_gh2_cosq_port_bandwidth_set(unit, local_port, i, 2875 kbits_sec_min, 2876 kbits_sec_max, 2877 kbits_burst, 2878 flags)); 2879 } 2880 } 2881 return BCM_E_NONE; 2882 } 2883 2884 BCM_IF_ERROR_RETURN 2885 (bcmi_gh2_cosq_gport_bandwidth_port_resolve(unit, gport, cosq, 2886 &local_port, 2887 &cosq_start, &cosq_end)); 2888 2889 for (i = cosq_start; i <= cosq_end; i++) { 2890 BCM_IF_ERROR_RETURN 2891 (bcmi_gh2_cosq_port_bandwidth_get(unit, gport, cosq_start, 2892 &kbits_sec_min, &kbits_sec_max, 2893 &kbits_sec_burst, &flags)); 2894 BCM_IF_ERROR_RETURN 2895 (bcmi_gh2_cosq_port_bandwidth_set(unit, gport, i, 2896 kbits_sec_min, 2897 kbits_sec_max, 2898 kbits_burst, 2899 flags)); 2900 } 2901 return BCM_E_NONE; 2902 } 2903 2904 /* 2905 * Function: 2906 * bcmi_gh2_cosq_gport_bandwidth_burst_get 2907 * Purpose: 2908 * 2909 * Parameters: 2910 * unit - (IN) Unit number. 2911 * gport - (IN) GPORT ID. 2912 * cosq - (IN) COS queue to configure, -1 for all COS queues. 2913 * kbits_burst - (OUT) maximum burst, kbits. 2914 * Returns: 2915 * BCM_E_XXX 2916 */ 2917 int 2918 bcmi_gh2_cosq_gport_bandwidth_burst_get(int unit, bcm_gport_t gport, 2919 bcm_cos_queue_t cosq, 2920 uint32 *kbits_burst) 2921 { 2922 bcm_port_t local_port, port; 2923 bcm_cos_queue_t cosq_start = 0, cosq_end = 0; 2924 uint32 kbits_sec_min, kbits_sec_max, flags; /* Dummy variables */ 2925 2926 kbits_sec_min = kbits_sec_max = flags = 0; 2927 2928 if (gport < 0) { 2929 port = SOC_PORT_MIN(unit, all); 2930 2931 BCM_IF_ERROR_RETURN 2932 (bcmi_gh2_cosq_gport_bandwidth_port_resolve( 2933 unit, port, cosq, 2934 &local_port, 2935 &cosq_start, &cosq_end)); 2936 BCM_IF_ERROR_RETURN 2937 (bcmi_gh2_cosq_port_bandwidth_get(unit, local_port, cosq_start, 2938 &kbits_sec_min, &kbits_sec_max, 2939 kbits_burst, &flags)); 2940 } else { 2941 BCM_IF_ERROR_RETURN 2942 (bcmi_gh2_cosq_gport_bandwidth_port_resolve( 2943 unit, gport, cosq, 2944 &local_port, 2945 &cosq_start, &cosq_end)); 2946 BCM_IF_ERROR_RETURN 2947 (bcmi_gh2_cosq_port_bandwidth_get(unit, gport, cosq_start, 2948 &kbits_sec_min, &kbits_sec_max, 2949 kbits_burst, &flags)); 2950 } 2951 2952 return BCM_E_NONE; 2953 } 2954 2955 /* 2956 * Function: 2957 * bcmi_gh2_cosq_control_set 2958 * Purpose: 2959 * Set specified feature configuration 2960 * 2961 * Parameters: 2962 * unit - (IN) Unit number. 2963 * port - (IN) GPORT ID. 2964 * cosq - (IN) COS queue. 2965 * type - (IN) feature 2966 * arg - (IN) feature value 2967 * Returns: 2968 * BCM_E_XXX 2969 * Notes: 2970 */ 2971 int 2972 bcmi_gh2_cosq_control_set(int unit, bcm_gport_t gport, bcm_cos_queue_t cosq, 2973 bcm_cosq_control_t type, int arg) 2974 { 2975 bcm_port_t port; 2976 int is_64q_port; 2977 soc_reg_t config_reg = INVALIDr; 2978 uint32 rval; 2979 uint32 fval = 0; 2980 int offset = 0; 2981 int hw_cosq_idx; 2982 2983 LOG_INFO(BSL_LS_BCM_COSQ, 2984 (BSL_META_U(unit, 2985 "bcmi_gh2_cosq_control_set: unit=%d gport=0x%x \ 2986 cosq=%d type=%d arg=%d\n"), 2987 unit, gport, cosq, type, arg)); 2988 2989 BCM_IF_ERROR_RETURN 2990 (bcmi_gh2_cosq_qlayer_scheduler_resolve(unit, gport, cosq, 2991 &port, &hw_cosq_idx)); 2992 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, port, &is_64q_port)); 2993 2994 switch (type) { 2995 case bcmCosqControlEEEQueueThresholdProfileSelect: 2996 if (is_64q_port) { 2997 config_reg = EEE_PROFILE_SEL_QLAYERr; 2998 } else { 2999 config_reg = EEE_PROFILE_SELr; 3000 } 3001 3002 BCM_IF_ERROR_RETURN( 3003 soc_reg32_get(unit, config_reg, port, hw_cosq_idx, &rval)); 3004 soc_reg_field_set(unit, config_reg, &rval, 3005 EEE_THRESH_SELf, arg); 3006 BCM_IF_ERROR_RETURN( 3007 soc_reg32_set(unit, config_reg, port, hw_cosq_idx, rval)); 3008 return BCM_E_NONE; 3009 break; 3010 case bcmCosqControlEEEPacketLatencyProfileSelect: 3011 if (is_64q_port) { 3012 config_reg = EEE_PROFILE_SEL_QLAYERr; 3013 } else { 3014 config_reg = EEE_PROFILE_SELr; 3015 } 3016 3017 BCM_IF_ERROR_RETURN( 3018 soc_reg32_get(unit, config_reg, port, hw_cosq_idx, &rval)); 3019 soc_reg_field_set(unit, config_reg, &rval, 3020 EEE_LATENCY_SELf, arg); 3021 BCM_IF_ERROR_RETURN( 3022 soc_reg32_set(unit, config_reg, port, hw_cosq_idx, rval)); 3023 return BCM_E_NONE; 3024 break; 3025 case bcmCosqControlAlternateStoreForward: 3026 if (is_64q_port) { 3027 if (hw_cosq_idx < 32) { 3028 config_reg = ASF_ENABLE_0_64Qr; 3029 } else { 3030 config_reg = ASF_ENABLE_1_64Qr; 3031 } 3032 offset = hw_cosq_idx % 32; 3033 } else { 3034 config_reg = ASF_ENABLE_8Qr; 3035 offset = hw_cosq_idx; 3036 } 3037 3038 BCM_IF_ERROR_RETURN( 3039 soc_reg32_get(unit, config_reg, port, 0, &rval)); 3040 fval = soc_reg_field_get(unit, config_reg, 3041 rval, ASF_ENABLEf); 3042 3043 if (arg == bcmCosqAsfModeAlternateStoreForward) { 3044 fval |= (1 << offset); 3045 } else { 3046 fval &= ~(1 << offset); 3047 } 3048 soc_reg_field_set(unit, config_reg, &rval, 3049 ASF_ENABLEf, fval); 3050 BCM_IF_ERROR_RETURN( 3051 soc_reg32_set(unit, config_reg, port, 0, rval)); 3052 return BCM_E_NONE; 3053 break; 3054 default: 3055 break; 3056 } 3057 3058 return BCM_E_UNAVAIL; 3059 } 3060 3061 /* 3062 * Function: 3063 * bcmi_gh2_cosq_control_get 3064 * Purpose: 3065 * Get specified feature configuration 3066 * 3067 * Parameters: 3068 * unit - (IN) Unit number. 3069 * port - (IN) GPORT ID. 3070 * cosq - (IN) COS queue. 3071 * type - (IN) feature 3072 * arg - (OUT) feature value 3073 * Returns: 3074 * BCM_E_XXX 3075 * Notes: 3076 */ 3077 int 3078 bcmi_gh2_cosq_control_get(int unit, bcm_gport_t gport, bcm_cos_queue_t cosq, 3079 bcm_cosq_control_t type, int *arg) 3080 { 3081 bcm_port_t port; 3082 int is_64q_port; 3083 soc_reg_t config_reg = INVALIDr; 3084 uint32 rval; 3085 uint32 fval = 0; 3086 int offset = 0; 3087 int hw_cosq_idx; 3088 3089 LOG_INFO(BSL_LS_BCM_COSQ, 3090 (BSL_META_U(unit, 3091 "bcmi_gh2_cosq_control_get: unit=%d gport=0x%x \ 3092 cosq=%d type=%d\n"), 3093 unit, gport, cosq, type)); 3094 if (arg == NULL) { 3095 return BCM_E_PARAM; 3096 } 3097 3098 BCM_IF_ERROR_RETURN 3099 (bcmi_gh2_cosq_qlayer_scheduler_resolve(unit, gport, cosq, 3100 &port, &hw_cosq_idx)); 3101 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, port, &is_64q_port)); 3102 3103 switch (type) { 3104 case bcmCosqControlEEEQueueThresholdProfileSelect: 3105 if (is_64q_port) { 3106 config_reg = EEE_PROFILE_SEL_QLAYERr; 3107 } else { 3108 config_reg = EEE_PROFILE_SELr; 3109 } 3110 3111 BCM_IF_ERROR_RETURN( 3112 soc_reg32_get(unit, config_reg, port, hw_cosq_idx, &rval)); 3113 *arg = soc_reg_field_get(unit, config_reg, 3114 rval, EEE_THRESH_SELf); 3115 return BCM_E_NONE; 3116 break; 3117 case bcmCosqControlEEEPacketLatencyProfileSelect: 3118 if (is_64q_port) { 3119 config_reg = EEE_PROFILE_SEL_QLAYERr; 3120 } else { 3121 config_reg = EEE_PROFILE_SELr; 3122 } 3123 3124 BCM_IF_ERROR_RETURN( 3125 soc_reg32_get(unit, config_reg, port, hw_cosq_idx, &rval)); 3126 *arg = soc_reg_field_get(unit, config_reg, 3127 rval, EEE_LATENCY_SELf); 3128 return BCM_E_NONE; 3129 break; 3130 case bcmCosqControlAlternateStoreForward: 3131 if (is_64q_port) { 3132 if (hw_cosq_idx < 32) { 3133 config_reg = ASF_ENABLE_0_64Qr; 3134 } else { 3135 config_reg = ASF_ENABLE_1_64Qr; 3136 } 3137 offset = hw_cosq_idx % 32; 3138 } else { 3139 config_reg = ASF_ENABLE_8Qr; 3140 offset = hw_cosq_idx; 3141 } 3142 3143 BCM_IF_ERROR_RETURN( 3144 soc_reg32_get(unit, config_reg, port, 0, &rval)); 3145 fval = soc_reg_field_get(unit, config_reg, 3146 rval, ASF_ENABLEf); 3147 if (fval & (1 << offset)) { 3148 *arg = bcmCosqAsfModeAlternateStoreForward; 3149 } else { 3150 *arg = bcmCosqAsfModeDisabled; 3151 } 3152 return BCM_E_NONE; 3153 break; 3154 default: 3155 break; 3156 } 3157 3158 return BCM_E_UNAVAIL; 3159 } 3160 3161 /* 3162 * Function: 3163 * bcmi_gh2_cosq_num_validate 3164 * Purpose: 3165 * validate cosq id 3166 * 3167 * Parameters: 3168 * unit - (IN) Unit number. 3169 * port - (IN) GPORT ID. 3170 * cosq - (IN) COS queue. 3171 * Returns: 3172 * BCM_E_XXX 3173 * Notes: 3174 */ 3175 STATIC int 3176 bcmi_gh2_cosq_num_validate(int unit, bcm_port_t port, int cosq) 3177 { 3178 int max_cosq_per_port; 3179 int is_64q_port; 3180 3181 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, port, &is_64q_port)); 3182 3183 if (is_64q_port) { 3184 max_cosq_per_port = SOC_GH2_2LEVEL_QUEUE_NUM; 3185 } else { 3186 max_cosq_per_port = SOC_GH2_LEGACY_QUEUE_NUM; 3187 } 3188 3189 if (((cosq >= 0) && (cosq < max_cosq_per_port)) || 3190 (cosq == BCM_COS_INVALID)) { 3191 return BCM_E_NONE; 3192 } 3193 3194 return BCM_E_PARAM; 3195 } 3196 3197 /* 3198 * Function: 3199 * bcmi_gh2_cosq_stat_get 3200 * Parameters: 3201 * unit - (IN) Unit number 3202 * gport - (IN) GPORT ID 3203 * cosq - (IN) COS queue. 3204 * stat - (IN) Statistic to be retrieved. 3205 * value - (OUT) Returned statistic value. 3206 * Returns: 3207 * BCM_E_XXX 3208 */ 3209 int 3210 bcmi_gh2_cosq_stat_get(int unit, bcm_gport_t gport, bcm_cos_queue_t cosq, 3211 bcm_cosq_stat_t stat, int sync_mode, uint64 *value) 3212 { 3213 bcm_port_t local_port; 3214 int (*counter_get) (int , soc_port_t , soc_reg_t , int , uint64 *); 3215 uint64 val64; 3216 int i, rv; 3217 int is_64q_port = 0; 3218 int total_cosq = 0; 3219 int cosq_idx = 0; 3220 3221 LOG_INFO(BSL_LS_BCM_COSQ, 3222 (BSL_META_U(unit, 3223 "bcmi_gh2_cosq_stat_get: unit=%d gport=0x%x \ 3224 cosq=%d stat=%d sync_mode=%d\n"), 3225 unit, gport, cosq, stat, sync_mode)); 3226 3227 if (value == NULL) { 3228 return BCM_E_PARAM; 3229 } 3230 3231 /* 3232 * if sync-mode is set, update the software cached counter value, 3233 * with the hardware count and then retrieve the count. 3234 * else return the software cache counter value. 3235 */ 3236 counter_get = (sync_mode == 1) ? soc_counter_sync_get : soc_counter_get; 3237 COMPILER_64_ZERO(*value); 3238 COMPILER_64_ZERO(val64); 3239 3240 switch (stat) { 3241 case bcmCosqStatDroppedPackets: 3242 if (cosq == BCM_COS_INVALID) { 3243 BCM_IF_ERROR_RETURN(bcmi_gh2_cosq_localport_resolve(unit, gport, 3244 &local_port)); 3245 /* 3246 * SOC_COUNTER_NON_DMA_COSQ_DROP_PKT gets the 3247 * EGRDROPPKTCOUNT_COSr which is a register array with 3248 * 64 elements per-port. 3249 */ 3250 for (i = 0; i < SOC_GH2_2LEVEL_QUEUE_NUM; i++) { 3251 rv = counter_get(unit, local_port, 3252 SOC_COUNTER_NON_DMA_COSQ_DROP_PKT, i, &val64); 3253 if (SOC_SUCCESS(rv)) { 3254 COMPILER_64_ADD_64(*value, val64); 3255 } else { 3256 break; 3257 } 3258 } 3259 } else { 3260 BCM_IF_ERROR_RETURN 3261 (bcmi_gh2_cosq_qlayer_scheduler_resolve(unit, gport, 3262 cosq, 3263 &local_port, 3264 &cosq_idx)); 3265 3266 SOC_IF_ERROR_RETURN(counter_get(unit, local_port, 3267 SOC_COUNTER_NON_DMA_COSQ_DROP_PKT, 3268 cosq_idx, value)); 3269 } 3270 break; 3271 case bcmCosqStatOutPackets: 3272 if (cosq == BCM_COS_INVALID) { 3273 BCM_IF_ERROR_RETURN(bcmi_gh2_cosq_localport_resolve(unit, gport, 3274 &local_port)); 3275 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port, 3276 &is_64q_port)); 3277 if (!is_64q_port) { 3278 total_cosq = SOC_GH2_LEGACY_QUEUE_NUM; 3279 } else { 3280 total_cosq = SOC_GH2_2LEVEL_QUEUE_NUM; 3281 } 3282 for (i = 0; i < total_cosq; i++) { 3283 rv = counter_get(unit, local_port, 3284 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT, 3285 i, &val64); 3286 if (SOC_SUCCESS(rv)) { 3287 COMPILER_64_ADD_64(*value, val64); 3288 } else { 3289 break; 3290 } 3291 } 3292 } else { 3293 BCM_IF_ERROR_RETURN 3294 (bcmi_gh2_cosq_qlayer_scheduler_resolve(unit, gport, 3295 cosq, 3296 &local_port, 3297 &cosq_idx)); 3298 SOC_IF_ERROR_RETURN 3299 (counter_get(unit, local_port, 3300 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT, 3301 cosq_idx, value)); 3302 } 3303 break; 3304 case bcmCosqStatOutBytes: 3305 if (cosq == BCM_COS_INVALID) { 3306 BCM_IF_ERROR_RETURN(bcmi_gh2_cosq_localport_resolve(unit, gport, 3307 &local_port)); 3308 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port, 3309 &is_64q_port)); 3310 if (!is_64q_port) { 3311 total_cosq = SOC_GH2_LEGACY_QUEUE_NUM; 3312 } else { 3313 total_cosq = SOC_GH2_2LEVEL_QUEUE_NUM; 3314 } 3315 for (i = 0; i < total_cosq; i++) { 3316 rv = counter_get(unit, local_port, 3317 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE, 3318 i, &val64); 3319 if (SOC_SUCCESS(rv)) { 3320 COMPILER_64_ADD_64(*value, val64); 3321 } else { 3322 break; 3323 } 3324 } 3325 } else { 3326 BCM_IF_ERROR_RETURN 3327 (bcmi_gh2_cosq_qlayer_scheduler_resolve(unit, gport, 3328 cosq, 3329 &local_port, 3330 &cosq_idx)); 3331 SOC_IF_ERROR_RETURN 3332 (counter_get(unit, local_port, 3333 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE, 3334 cosq_idx, value)); 3335 } 3336 break; 3337 case bcmCosqStatYellowCongestionDroppedPackets: 3338 BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, gport, 3339 &local_port)); 3340 BCM_IF_ERROR_RETURN(bcmi_gh2_cosq_num_validate(unit, local_port, cosq)); 3341 if (cosq != BCM_COS_INVALID) { 3342 /* Yellow dropped packet counters are available only on a per 3343 * port basis. 3344 */ 3345 return BCM_E_UNAVAIL; 3346 } 3347 SOC_IF_ERROR_RETURN 3348 (counter_get(unit, local_port, 3349 SOC_COUNTER_NON_DMA_PORT_DROP_PKT_YELLOW, 0, value)); 3350 break; 3351 case bcmCosqStatRedCongestionDroppedPackets: 3352 BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, gport, 3353 &local_port)); 3354 BCM_IF_ERROR_RETURN(bcmi_gh2_cosq_num_validate(unit, local_port, cosq)); 3355 if (cosq != BCM_COS_INVALID) { 3356 /* Red dropped packet counters are available only on a per 3357 * port basis. 3358 */ 3359 return BCM_E_UNAVAIL; 3360 } 3361 SOC_IF_ERROR_RETURN(counter_get(unit, local_port, 3362 SOC_COUNTER_NON_DMA_PORT_DROP_PKT_RED, 3363 0, value)); 3364 break; 3365 case bcmCosqStatDiscardDroppedPackets: 3366 if (soc_feature(unit, soc_feature_wred_drop_counter_per_port)) { 3367 BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, gport, 3368 &local_port)); 3369 BCM_IF_ERROR_RETURN(bcmi_gh2_cosq_num_validate(unit, local_port, 3370 cosq)); 3371 COMPILER_64_ZERO(*value); 3372 if (cosq == BCM_COS_INVALID) { 3373 SOC_IF_ERROR_RETURN 3374 (soc_counter_get(unit, local_port, 3375 SOC_COUNTER_NON_DMA_PORT_WRED_DROP_PKT, 3376 0, value)); 3377 } else { 3378 return BCM_E_UNAVAIL; 3379 } 3380 } 3381 break; 3382 case bcmCosqStatTASTxOverrunPackets: 3383 if (soc_feature(unit, soc_feature_tas)) { 3384 BCM_IF_ERROR_RETURN( 3385 _bcm_esw_port_gport_validate(unit, gport, &local_port)); 3386 BCM_IF_ERROR_RETURN( 3387 bcmi_gh2_tas_port_validate(unit, local_port)); 3388 if (cosq != BCM_COS_INVALID) { 3389 /* Only support per port basis */ 3390 return BCM_E_UNAVAIL; 3391 } 3392 COMPILER_64_ZERO(*value); 3393 COMPILER_64_ZERO(val64); 3394 SOC_IF_ERROR_RETURN( 3395 counter_get(unit, local_port, 3396 SOC_COUNTER_NON_DMA_TAS_TXOVERRUN_PREEMPT, 3397 0, &val64)); 3398 COMPILER_64_ADD_64(*value, val64); 3399 3400 COMPILER_64_ZERO(val64); 3401 SOC_IF_ERROR_RETURN( 3402 counter_get(unit, local_port, 3403 SOC_COUNTER_NON_DMA_TAS_TXOVERRUN_EXPRESS, 3404 0, &val64)); 3405 COMPILER_64_ADD_64(*value, val64); 3406 } 3407 break; 3408 default: 3409 return BCM_E_PARAM; 3410 } 3411 3412 return BCM_E_NONE; 3413 } 3414 3415 /* 3416 * Function: 3417 * bcmi_gh2_cosq_stat_set 3418 * Purpose: 3419 * Set statistics 3420 * Parameters: 3421 * unit - (IN) Unit number. 3422 * gport - (IN) GPORT ID 3423 * cosq - (IN) COS queue. 3424 * stat - (IN) Statistic to be set. 3425 * value - (IN) Statistic value to be set. 3426 * Returns: 3427 * BCM_E_xxx 3428 * Notes: 3429 */ 3430 int 3431 bcmi_gh2_cosq_stat_set(int unit, bcm_gport_t gport, bcm_cos_queue_t cosq, 3432 bcm_cosq_stat_t stat, uint64 value) 3433 { 3434 bcm_port_t local_port; 3435 uint64 val64_zero; 3436 int i, rv; 3437 int is_64q_port = 0; 3438 int total_cosq = 0; 3439 int cosq_idx = 0; 3440 3441 LOG_INFO(BSL_LS_BCM_COSQ, 3442 (BSL_META_U(unit, 3443 "bcmi_gh2_cosq_stat_set: unit=%d gport=0x%x \ 3444 cosq=%d stat=%d\n"), 3445 unit, gport, cosq, stat)); 3446 3447 switch (stat) { 3448 case bcmCosqStatOutPackets: 3449 COMPILER_64_ZERO(val64_zero); 3450 if (cosq == BCM_COS_INVALID) { 3451 BCM_IF_ERROR_RETURN(bcmi_gh2_cosq_localport_resolve(unit, gport, 3452 &local_port)); 3453 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port, 3454 &is_64q_port)); 3455 if (!is_64q_port) { 3456 total_cosq = SOC_GH2_LEGACY_QUEUE_NUM; 3457 } else { 3458 total_cosq = SOC_GH2_2LEVEL_QUEUE_NUM; 3459 } 3460 /* Write given value to first COS queue */ 3461 rv = soc_counter_set(unit, local_port, 3462 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT, 3463 0, value); 3464 3465 /* Write zero to all other COS queues */ 3466 for (i = 1; i < total_cosq; i++) { 3467 rv = soc_counter_set(unit, local_port, 3468 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT, 3469 i, val64_zero); 3470 if (SOC_FAILURE(rv)) { 3471 break; 3472 } 3473 } 3474 } else { 3475 BCM_IF_ERROR_RETURN 3476 (bcmi_gh2_cosq_qlayer_scheduler_resolve(unit, gport, 3477 cosq, 3478 &local_port, 3479 &cosq_idx)); 3480 SOC_IF_ERROR_RETURN 3481 (soc_counter_set(unit, local_port, 3482 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT, 3483 cosq_idx, value)); 3484 } 3485 break; 3486 case bcmCosqStatOutBytes: 3487 COMPILER_64_ZERO(val64_zero); 3488 if (cosq == BCM_COS_INVALID) { 3489 BCM_IF_ERROR_RETURN(bcmi_gh2_cosq_localport_resolve(unit, gport, 3490 &local_port)); 3491 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port, 3492 &is_64q_port)); 3493 if (!is_64q_port) { 3494 total_cosq = SOC_GH2_LEGACY_QUEUE_NUM; 3495 } else { 3496 total_cosq = SOC_GH2_2LEVEL_QUEUE_NUM; 3497 } 3498 3499 /* Write given value to first COS queue */ 3500 rv = soc_counter_set(unit, local_port, 3501 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE, 3502 0, value); 3503 3504 /* Write zero to all other COS queues */ 3505 for (i = 1; i < total_cosq; i++) { 3506 rv = soc_counter_set(unit, local_port, 3507 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE, 3508 i, val64_zero); 3509 if (SOC_FAILURE(rv)) { 3510 break; 3511 } 3512 } 3513 } else { 3514 BCM_IF_ERROR_RETURN 3515 (bcmi_gh2_cosq_qlayer_scheduler_resolve(unit, gport, 3516 cosq, 3517 &local_port, 3518 &cosq_idx)); 3519 SOC_IF_ERROR_RETURN 3520 (soc_counter_set(unit, local_port, 3521 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE, 3522 cosq_idx, value)); 3523 } 3524 break; 3525 case bcmCosqStatDiscardDroppedPackets: 3526 if (soc_feature(unit, soc_feature_wred_drop_counter_per_port)) { 3527 BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, gport, 3528 &local_port)); 3529 if (cosq == BCM_COS_INVALID) { 3530 SOC_IF_ERROR_RETURN 3531 (soc_counter_set(unit, local_port, 3532 SOC_COUNTER_NON_DMA_PORT_WRED_DROP_PKT, 3533 0, value)); 3534 } else { 3535 return BCM_E_UNAVAIL; 3536 } 3537 } 3538 break; 3539 case bcmCosqStatTASTxOverrunPackets: 3540 if (soc_feature(unit, soc_feature_tas)) { 3541 /* read-only register, only take value=0 to clear it */ 3542 if (!COMPILER_64_IS_ZERO(value)) { 3543 return BCM_E_UNAVAIL; 3544 } 3545 BCM_IF_ERROR_RETURN( 3546 _bcm_esw_port_gport_validate(unit, gport, &local_port)); 3547 if (cosq == BCM_COS_INVALID) { 3548 SOC_IF_ERROR_RETURN( 3549 soc_counter_set(unit, local_port, 3550 SOC_COUNTER_NON_DMA_TAS_TXOVERRUN_EXPRESS, 3551 0, value)); 3552 } else { 3553 return BCM_E_UNAVAIL; 3554 } 3555 } 3556 break; 3557 case bcmCosqStatDroppedPackets: 3558 case bcmCosqStatYellowCongestionDroppedPackets: 3559 case bcmCosqStatRedCongestionDroppedPackets: 3560 /* registers are read-only */ 3561 return BCM_E_UNAVAIL; 3562 default: 3563 return BCM_E_PARAM; 3564 } 3565 3566 return BCM_E_NONE; 3567 } 3568 3569 /* 3570 * Convert HW drop probability to percent value 3571 */ 3572 STATIC int 3573 gh2_hw_drop_prob_to_percent[] = { 3574 0, /* 0 */ 3575 1, /* 1 */ 3576 2, /* 2 */ 3577 3, /* 3 */ 3578 4, /* 4 */ 3579 5, /* 5 */ 3580 6, /* 6 */ 3581 7, /* 7 */ 3582 8, /* 8 */ 3583 9, /* 9 */ 3584 10, /* 10 */ 3585 25, /* 11 */ 3586 50, /* 12 */ 3587 75, /* 13 */ 3588 100, /* 14 */ 3589 -1 /* 15 */ 3590 }; 3591 3592 STATIC int 3593 bcmi_gh2_percent_to_drop_prob(int percent) 3594 { 3595 int i; 3596 3597 for (i = 14; i > 0 ; i--) { 3598 if (percent >= gh2_hw_drop_prob_to_percent[i]) { 3599 break; 3600 } 3601 } 3602 return i; 3603 } 3604 3605 STATIC int 3606 bcmi_gh2_drop_prob_to_percent(int drop_prob) { 3607 return (gh2_hw_drop_prob_to_percent[drop_prob]); 3608 } 3609 3610 /* 3611 * index: degree, value: contangent(degree) * 100 3612 * max value is 0x7fff (15-bit) at 0 degree 3613 */ 3614 STATIC int 3615 bcmi_gh2_cotangent_lookup_table[] = 3616 { 3617 /* 0.. 5 */ 32767, 5728, 2863, 1908, 1430, 1143, 3618 /* 6..11 */ 951, 814, 711, 631, 567, 514, 3619 /* 12..17 */ 470, 433, 401, 373, 348, 327, 3620 /* 18..23 */ 307, 290, 274, 260, 247, 235, 3621 /* 24..29 */ 224, 214, 205, 196, 188, 180, 3622 /* 30..35 */ 173, 166, 160, 153, 148, 142, 3623 /* 36..41 */ 137, 132, 127, 123, 119, 115, 3624 /* 42..47 */ 111, 107, 103, 100, 96, 93, 3625 /* 48..53 */ 90, 86, 83, 80, 78, 75, 3626 /* 54..59 */ 72, 70, 67, 64, 62, 60, 3627 /* 60..65 */ 57, 55, 53, 50, 48, 46, 3628 /* 66..71 */ 44, 42, 40, 38, 36, 34, 3629 /* 72..77 */ 32, 30, 28, 26, 24, 23, 3630 /* 78..83 */ 21, 19, 17, 15, 14, 12, 3631 /* 84..89 */ 10, 8, 6, 5, 3, 1, 3632 /* 90 */ 0 3633 }; 3634 3635 /* 3636 * Given a slope (angle in degrees) from 0 to 90, return the number of cells 3637 * in the range from 0% drop probability to 100% drop probability. 3638 */ 3639 STATIC int 3640 bcmi_gh2_angle_to_cells(int angle) 3641 { 3642 return (bcmi_gh2_cotangent_lookup_table[angle]); 3643 } 3644 3645 /* 3646 * Given a number of packets in the range from 0% drop probability 3647 * to 100% drop probability, return the slope (angle in degrees). 3648 */ 3649 STATIC int 3650 bcmi_gh2_cells_to_angle(int packets) 3651 { 3652 int angle; 3653 3654 for (angle = 90; angle >= 0 ; angle--) { 3655 if (packets <= bcmi_gh2_cotangent_lookup_table[angle]) { 3656 break; 3657 } 3658 } 3659 return angle; 3660 } 3661 3662 /* 3663 * Function: 3664 * bcmi_gh2_cosq_wred_set 3665 * Purpose: 3666 * Configure queue WRED setting 3667 * Parameters: 3668 * unit - (IN) unit number 3669 * port - (IN) port number or GPORT identifier 3670 * cosq - (IN) COS queue number 3671 * flags - (IN) BCM_COSQ_DISCARD_XXX 3672 * min_thresh - (IN) 3673 * max_thresh - (IN) 3674 * drop_probablity - (IN) 3675 * gain - (IN) 3676 * ignore_enable_flags - (IN) 3677 * Returns: 3678 * BCM_E_XXX 3679 * Notes: 3680 * If port is any form of local port, cosq is the hardware queue index. 3681 */ 3682 STATIC int 3683 bcmi_gh2_cosq_wred_set(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 3684 uint32 flags, uint32 min_thresh, uint32 max_thresh, 3685 int drop_probability, int gain, int ignore_enable_flags, 3686 uint32 lflags) 3687 { 3688 int index; 3689 uint32 profile_index, old_profile_index; 3690 mmu_wred_drop_profile_green_entry_t entry_tcp_green; 3691 mmu_wred_drop_profile_yellow_entry_t entry_tcp_yellow; 3692 mmu_wred_drop_profile_red_entry_t entry_tcp_red; 3693 mmu_wred_mark_profile_green_entry_t entry_mark_green; 3694 mmu_wred_mark_profile_yellow_entry_t entry_mark_yellow; 3695 mmu_wred_mark_profile_red_entry_t entry_mark_red; 3696 mmu_wred_config_entry_t qentry; 3697 void *entries[6]; 3698 soc_mem_t mems[6]; 3699 int rate, i, exists = 0; 3700 static soc_mem_t wred_mems[6] = { 3701 MMU_WRED_DROP_PROFILE_GREENm, 3702 MMU_WRED_DROP_PROFILE_YELLOWm, 3703 MMU_WRED_DROP_PROFILE_REDm, 3704 MMU_WRED_MARK_PROFILE_GREENm, 3705 MMU_WRED_MARK_PROFILE_YELLOWm, 3706 MMU_WRED_MARK_PROFILE_REDm 3707 }; 3708 int is_64q_port = 0; 3709 soc_mem_t config_mem = INVALIDm; 3710 gh2_cosq_node_t *node; 3711 bcm_port_t local_port; 3712 int local_cosq = 0; 3713 3714 /* 3715 * if (port is GPORT scheduler) 3716 * cosq is the child index of the GPORT object (QGROUP or QLAYER) 3717 * valid value : 0~7 3718 * otherwise (just resolve the local port id) 3719 * cosq is COSQ number, value 0~7 or 0~63 3720 */ 3721 if (BCM_GPORT_IS_SCHEDULER(port)) { 3722 BCM_IF_ERROR_RETURN 3723 (bcmi_gh2_cosq_node_get(unit, port, 0, NULL, 3724 &local_port, NULL, &node)); 3725 if (node->node_level == GH2_COSQ_LEVEL_QGROUP) { 3726 if ((cosq < 0) || 3727 (cosq >= SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM)) { 3728 return BCM_E_PARAM; 3729 } 3730 3731 config_mem = MMU_WRED_CONFIG_QGROUPm; 3732 /* Get the MMU_WRED_CONFIG_QGROUPm index by (port, cosq) */ 3733 BCM_IF_ERROR_RETURN(soc_gh2_mmu_bucket_qgroup_index 3734 (unit, local_port, cosq, &index)); 3735 } else if (node->node_level == GH2_COSQ_LEVEL_QLAYER) { 3736 if ((cosq < 0) || 3737 (cosq >= SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM)) { 3738 return BCM_E_PARAM; 3739 } 3740 config_mem = MMU_WRED_CONFIGm; 3741 local_cosq = node->qlayer_cosq_min + cosq; 3742 /* Get the MMU_WRED_CONFIGm index by (port, cosq) */ 3743 BCM_IF_ERROR_RETURN(soc_gh2_mmu_bucket_qlayer_index 3744 (unit, local_port, local_cosq, &index)); 3745 } else { 3746 return BCM_E_PARAM; 3747 } 3748 } else { 3749 BCM_IF_ERROR_RETURN 3750 (bcmi_gh2_cosq_localport_resolve(unit, port, &local_port)); 3751 3752 if (!SOC_PORT_VALID(unit, local_port) || 3753 (CMIC_PORT(unit) == local_port)) { 3754 return BCM_E_PORT; 3755 } 3756 3757 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port, 3758 &is_64q_port)); 3759 /* cosq parameter is value */ 3760 if (is_64q_port) { 3761 if ((cosq < 0) || cosq >= SOC_GH2_2LEVEL_QUEUE_NUM) { 3762 return BCM_E_PARAM; 3763 } 3764 } else { 3765 if ((cosq < 0) || cosq >= SOC_GH2_LEGACY_QUEUE_NUM) { 3766 return BCM_E_PARAM; 3767 } 3768 } 3769 3770 local_cosq = cosq; 3771 config_mem = MMU_WRED_CONFIGm; 3772 /* Get the MMU_WRED_CONFIGm index by (port, cosq) */ 3773 BCM_IF_ERROR_RETURN(soc_gh2_mmu_bucket_qlayer_index 3774 (unit, local_port, local_cosq, &index)); 3775 } 3776 3777 if (index < 0) { 3778 return BCM_E_PARAM; 3779 } 3780 3781 BCM_IF_ERROR_RETURN 3782 (soc_mem_read(unit, config_mem, SOC_BLOCK_ALL, index, &qentry)); 3783 3784 old_profile_index = 0xffffffff; 3785 3786 if (flags & BCM_COSQ_DISCARD_NONTCP) { 3787 /* Greyhound-based WRED doesnot support non-responsive dropping */ 3788 return BCM_E_UNAVAIL; 3789 } 3790 3791 if (flags & (BCM_COSQ_DISCARD_TCP | BCM_COSQ_DISCARD_COLOR_ALL | 3792 BCM_COSQ_DISCARD_MARK_CONGESTION)) { 3793 old_profile_index = soc_mem_field32_get(unit, config_mem, 3794 &qentry, PROFILE_INDEXf); 3795 entries[0] = &entry_tcp_green; 3796 entries[1] = &entry_tcp_yellow; 3797 entries[2] = &entry_tcp_red; 3798 entries[3] = &entry_mark_green; 3799 entries[4] = &entry_mark_yellow; 3800 entries[5] = &entry_mark_red; 3801 BCM_IF_ERROR_RETURN 3802 (soc_profile_mem_get(unit, gh2_wred_profile[unit], 3803 old_profile_index, 1, entries)); 3804 for (i = 0; i < 6; i++) { 3805 mems[i] = INVALIDm; 3806 } 3807 if ((flags & BCM_COSQ_DISCARD_TCP) || 3808 !(flags & BCM_COSQ_DISCARD_MARK_CONGESTION)) { 3809 if (flags & BCM_COSQ_DISCARD_COLOR_GREEN) { 3810 mems[0] = MMU_WRED_DROP_PROFILE_GREENm; 3811 } 3812 if (flags & BCM_COSQ_DISCARD_COLOR_YELLOW) { 3813 mems[1] = MMU_WRED_DROP_PROFILE_YELLOWm; 3814 } 3815 if (flags & BCM_COSQ_DISCARD_COLOR_RED) { 3816 mems[2] = MMU_WRED_DROP_PROFILE_REDm; 3817 } 3818 } 3819 if (flags & BCM_COSQ_DISCARD_MARK_CONGESTION) { 3820 if (flags & BCM_COSQ_DISCARD_COLOR_GREEN) { 3821 mems[3] = MMU_WRED_MARK_PROFILE_GREENm; 3822 } 3823 if (flags & BCM_COSQ_DISCARD_COLOR_YELLOW) { 3824 mems[4] = MMU_WRED_MARK_PROFILE_YELLOWm; 3825 } 3826 if (flags & BCM_COSQ_DISCARD_COLOR_RED) { 3827 mems[5] = MMU_WRED_MARK_PROFILE_REDm; 3828 } 3829 } 3830 rate = bcmi_gh2_percent_to_drop_prob(drop_probability); 3831 for (i = 0; i < 6; i++) { 3832 exists = 0; 3833 if ((soc_mem_field32_get(unit, wred_mems[i], entries[i], 3834 MIN_THDf) != GH2_CELL_FIELD_MAX) && (mems[i] == INVALIDm)) { 3835 mems[i] = wred_mems[i]; 3836 exists = 1; 3837 } else { 3838 soc_mem_field32_set(unit, wred_mems[i], entries[i], 3839 MIN_THDf, (mems[i] == INVALIDm) ? 3840 GH2_CELL_FIELD_MAX : min_thresh); 3841 } 3842 3843 if ((soc_mem_field32_get(unit, wred_mems[i], entries[i], 3844 MAX_THDf) != GH2_CELL_FIELD_MAX) && 3845 ((mems[i] == INVALIDm) || exists)) { 3846 mems[i] = wred_mems[i]; 3847 exists = 1; 3848 } else { 3849 soc_mem_field32_set(unit, wred_mems[i], entries[i], 3850 MAX_THDf, (mems[i] == INVALIDm) ? 3851 GH2_CELL_FIELD_MAX :max_thresh); 3852 } 3853 3854 if (!exists) { 3855 if (soc_mem_field_valid(unit, wred_mems[i], 3856 MAX_DROP_RATEf)) { 3857 soc_mem_field32_set(unit, wred_mems[i], entries[i], 3858 MAX_DROP_RATEf, (mems[i] == INVALIDm) ? 0 : rate); 3859 } else if (soc_mem_field_valid(unit, wred_mems[i], 3860 MAX_MARK_RATEf)) { 3861 soc_mem_field32_set(unit, wred_mems[i], entries[i], 3862 MAX_MARK_RATEf, (mems[i] == INVALIDm) ? 0 : rate); 3863 } 3864 } 3865 } 3866 BCM_IF_ERROR_RETURN 3867 (soc_profile_mem_add(unit, gh2_wred_profile[unit], 3868 entries, 1, &profile_index)); 3869 soc_mem_field32_set(unit, config_mem, 3870 &qentry, PROFILE_INDEXf, profile_index); 3871 soc_mem_field32_set(unit, config_mem, &qentry, WEIGHTf, gain); 3872 } 3873 /* Some APIs only modify profiles */ 3874 if (!ignore_enable_flags) { 3875 soc_mem_field32_set(unit, config_mem, &qentry, CAP_AVGf, 3876 flags & BCM_COSQ_DISCARD_CAP_AVERAGE ? 1 : 0); 3877 soc_mem_field32_set(unit, config_mem, &qentry, WRED_ENf, 3878 flags & BCM_COSQ_DISCARD_ENABLE ? 1 : 0); 3879 soc_mem_field32_set(unit, config_mem, &qentry, ECN_MARKING_ENf, 3880 flags & BCM_COSQ_DISCARD_MARK_CONGESTION ? 1 : 0); 3881 } 3882 3883 BCM_IF_ERROR_RETURN( 3884 soc_mem_write(unit, config_mem, MEM_BLOCK_ALL, index, &qentry)); 3885 3886 if (old_profile_index != 0xffffffff) { 3887 SOC_IF_ERROR_RETURN 3888 (soc_profile_mem_delete(unit, gh2_wred_profile[unit], 3889 old_profile_index)); 3890 } 3891 3892 return BCM_E_NONE; 3893 } 3894 3895 /* 3896 * Function: 3897 * bcmi_gh2_cosq_wred_get 3898 * Purpose: 3899 * Get queue WRED setting 3900 * Parameters: 3901 * unit - (IN) unit number 3902 * port - (IN) port number or GPORT identifier 3903 * cosq - (IN) COS queue number 3904 * flags - (IN/OUT) BCM_COSQ_DISCARD_XXX 3905 * min_thresh - (OUT) 3906 * max_thresh - (OUT) 3907 * drop_probablity - (OUT) 3908 * gain - (OUT) 3909 * Returns: 3910 * BCM_E_XXX 3911 * Notes: 3912 * If port is any form of local port, cosq is the hardware queue index. 3913 */ 3914 STATIC int 3915 bcmi_gh2_cosq_wred_get(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 3916 uint32 *flags, uint32 *min_thresh, uint32 *max_thresh, 3917 int *drop_probability, int *gain, uint32 lflags) 3918 { 3919 int index, profile_index; 3920 mmu_wred_drop_profile_green_entry_t entry_tcp_green; 3921 mmu_wred_drop_profile_yellow_entry_t entry_tcp_yellow; 3922 mmu_wred_drop_profile_red_entry_t entry_tcp_red; 3923 mmu_wred_mark_profile_green_entry_t entry_mark_green; 3924 mmu_wred_mark_profile_yellow_entry_t entry_mark_yellow; 3925 mmu_wred_mark_profile_red_entry_t entry_mark_red; 3926 void *entries[6]; 3927 void *entry_p = NULL; 3928 soc_mem_t profile_mem = INVALIDm; 3929 mmu_wred_config_entry_t qentry; 3930 int rate = 0; 3931 int is_64q_port = 0; 3932 soc_mem_t config_mem = INVALIDm; 3933 gh2_cosq_node_t *node; 3934 bcm_port_t local_port; 3935 int local_cosq = 0; 3936 3937 /* 3938 * if (port is GPORT scheduler) 3939 * cosq is the child index of the GPORT object (QGROUP or QLAYER) 3940 * otherwise (just resolve the local port id) 3941 * cosq is COSQ number, value 0~7 or 0~63 3942 */ 3943 if (BCM_GPORT_IS_SCHEDULER(port)) { 3944 BCM_IF_ERROR_RETURN 3945 (bcmi_gh2_cosq_node_get(unit, port, 0, NULL, 3946 &local_port, NULL, &node)); 3947 if (node->node_level == GH2_COSQ_LEVEL_QGROUP) { 3948 if ((cosq < 0) || 3949 (cosq >= SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM)) { 3950 return BCM_E_PARAM; 3951 } 3952 3953 config_mem = MMU_WRED_CONFIG_QGROUPm; 3954 /* Get the MMU_WRED_CONFIG_QGROUPm index by (port, cosq) */ 3955 BCM_IF_ERROR_RETURN(soc_gh2_mmu_bucket_qgroup_index 3956 (unit, local_port, cosq, &index)); 3957 } else if (node->node_level == GH2_COSQ_LEVEL_QLAYER) { 3958 if ((cosq < 0) || 3959 (cosq >= SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM)) { 3960 return BCM_E_PARAM; 3961 } 3962 3963 config_mem = MMU_WRED_CONFIGm; 3964 local_cosq = node->qlayer_cosq_min + cosq; 3965 /* Get the MMU_WRED_CONFIGm index by (port, cosq) */ 3966 BCM_IF_ERROR_RETURN(soc_gh2_mmu_bucket_qlayer_index 3967 (unit, local_port, local_cosq, &index)); 3968 } else { 3969 return BCM_E_PARAM; 3970 } 3971 } else { 3972 BCM_IF_ERROR_RETURN 3973 (bcmi_gh2_cosq_localport_resolve(unit, port, &local_port)); 3974 3975 if (!SOC_PORT_VALID(unit, local_port) || 3976 (CMIC_PORT(unit) == local_port)) { 3977 return BCM_E_PORT; 3978 } 3979 3980 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port, 3981 &is_64q_port)); 3982 3983 /* cosq parameter is value */ 3984 if (is_64q_port) { 3985 if ((cosq < 0) || cosq >= SOC_GH2_2LEVEL_QUEUE_NUM) { 3986 return BCM_E_PARAM; 3987 } 3988 } else { 3989 if ((cosq < 0) || cosq >= SOC_GH2_LEGACY_QUEUE_NUM) { 3990 return BCM_E_PARAM; 3991 } 3992 } 3993 3994 local_cosq = cosq; 3995 config_mem = MMU_WRED_CONFIGm; 3996 /* Get the MMU_WRED_CONFIGm index by (port, cosq) */ 3997 BCM_IF_ERROR_RETURN(soc_gh2_mmu_bucket_qlayer_index 3998 (unit, local_port, local_cosq, &index)); 3999 } 4000 if (index < 0) { 4001 return BCM_E_PARAM; 4002 } 4003 4004 4005 BCM_IF_ERROR_RETURN 4006 (soc_mem_read(unit, config_mem, MEM_BLOCK_ALL, index, &qentry)); 4007 profile_index = soc_mem_field32_get(unit, config_mem, 4008 &qentry, PROFILE_INDEXf); 4009 4010 if (*flags & BCM_COSQ_DISCARD_MARK_CONGESTION) { 4011 if (*flags & BCM_COSQ_DISCARD_COLOR_GREEN) { 4012 profile_mem = MMU_WRED_MARK_PROFILE_GREENm; 4013 entry_p = &entry_mark_green; 4014 } else if (*flags & BCM_COSQ_DISCARD_COLOR_YELLOW) { 4015 profile_mem = MMU_WRED_MARK_PROFILE_YELLOWm; 4016 entry_p = &entry_mark_yellow; 4017 } else if (*flags & BCM_COSQ_DISCARD_COLOR_RED) { 4018 profile_mem = MMU_WRED_MARK_PROFILE_REDm; 4019 entry_p = &entry_mark_red; 4020 } else { 4021 profile_mem = MMU_WRED_MARK_PROFILE_GREENm; 4022 entry_p = &entry_mark_green; 4023 } 4024 } else { 4025 if (*flags & BCM_COSQ_DISCARD_COLOR_GREEN) { 4026 profile_mem = MMU_WRED_DROP_PROFILE_GREENm; 4027 entry_p = &entry_tcp_green; 4028 } else if (*flags & BCM_COSQ_DISCARD_COLOR_YELLOW) { 4029 profile_mem = MMU_WRED_DROP_PROFILE_YELLOWm; 4030 entry_p = &entry_tcp_yellow; 4031 } else if (*flags & BCM_COSQ_DISCARD_COLOR_RED) { 4032 profile_mem = MMU_WRED_DROP_PROFILE_REDm; 4033 entry_p = &entry_tcp_red; 4034 } else { 4035 profile_mem = MMU_WRED_DROP_PROFILE_GREENm; 4036 entry_p = &entry_tcp_green; 4037 } 4038 } 4039 4040 entries[0] = &entry_tcp_green; 4041 entries[1] = &entry_tcp_yellow; 4042 entries[2] = &entry_tcp_red; 4043 entries[3] = &entry_mark_green; 4044 entries[4] = &entry_mark_yellow; 4045 entries[5] = &entry_mark_red; 4046 BCM_IF_ERROR_RETURN 4047 (soc_profile_mem_get(unit, gh2_wred_profile[unit], 4048 profile_index, 1, entries)); 4049 if (min_thresh != NULL) { 4050 *min_thresh = soc_mem_field32_get(unit, profile_mem, entry_p, MIN_THDf); 4051 } 4052 if (max_thresh != NULL) { 4053 *max_thresh = soc_mem_field32_get(unit, profile_mem, entry_p, MAX_THDf); 4054 } 4055 if (drop_probability != NULL) { 4056 if (soc_mem_field_valid(unit, profile_mem, MAX_DROP_RATEf)) { 4057 rate = soc_mem_field32_get( 4058 unit, profile_mem, entry_p, MAX_DROP_RATEf); 4059 } else if (soc_mem_field_valid(unit, profile_mem, MAX_MARK_RATEf)) { 4060 rate = soc_mem_field32_get( 4061 unit, profile_mem, entry_p, MAX_MARK_RATEf); 4062 } 4063 *drop_probability = bcmi_gh2_drop_prob_to_percent(rate); 4064 } 4065 4066 if (gain) { 4067 *gain = soc_mem_field32_get(unit, config_mem, &qentry, WEIGHTf); 4068 } 4069 4070 *flags &= ~(BCM_COSQ_DISCARD_CAP_AVERAGE | BCM_COSQ_DISCARD_ENABLE); 4071 if (soc_mem_field32_get(unit, config_mem, &qentry, CAP_AVGf)) { 4072 *flags |= BCM_COSQ_DISCARD_CAP_AVERAGE; 4073 } 4074 if (soc_mem_field32_get(unit, config_mem, &qentry, WRED_ENf)) { 4075 *flags |= BCM_COSQ_DISCARD_ENABLE; 4076 } 4077 if (soc_mem_field32_get(unit, config_mem, &qentry, ECN_MARKING_ENf)) { 4078 *flags |= BCM_COSQ_DISCARD_MARK_CONGESTION; 4079 } 4080 return BCM_E_NONE; 4081 } 4082 4083 int 4084 bcmi_gh2_cosq_discard_set(int unit, uint32 flags) 4085 { 4086 bcm_port_t port; 4087 int numq, i; 4088 int is_64q_port = 0; 4089 4090 flags &= ~(BCM_COSQ_DISCARD_NONTCP | BCM_COSQ_DISCARD_COLOR_ALL); 4091 4092 PBMP_PORT_ITER(unit, port) { 4093 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, port, 4094 &is_64q_port)); 4095 if (is_64q_port) { 4096 numq = SOC_GH2_2LEVEL_QUEUE_NUM; 4097 } else { 4098 numq = SOC_GH2_LEGACY_QUEUE_NUM; 4099 } 4100 for (i = 0; i < numq; i++) { 4101 BCM_IF_ERROR_RETURN 4102 (bcmi_gh2_cosq_wred_set(unit, port, i, flags, 0, 0, 0, 0, 4103 FALSE, BCM_COSQ_DISCARD_PORT)); 4104 } 4105 } 4106 4107 return BCM_E_NONE; 4108 } 4109 4110 int 4111 bcmi_gh2_cosq_discard_get(int unit, uint32 *flags) 4112 { 4113 bcm_port_t port; 4114 4115 PBMP_PORT_ITER(unit, port) { 4116 *flags = 0; 4117 return bcmi_gh2_cosq_wred_get(unit, port, 0, flags, NULL, NULL, NULL, 4118 NULL, BCM_COSQ_DISCARD_PORT); 4119 } 4120 4121 return BCM_E_NOT_FOUND; 4122 } 4123 4124 /* 4125 * Function: 4126 * bcmi_gh2_cosq_gport_discard_set 4127 * Purpose: 4128 * Configure port WRED setting 4129 * Parameters: 4130 * unit - (IN) unit number 4131 * port - (IN) GPORT identifier 4132 * cosq - (IN) COS queue to configure, -1 for all COS queues 4133 * discard - (IN) discard settings 4134 * Returns: 4135 * BCM_E_XXX 4136 */ 4137 4138 int 4139 bcmi_gh2_cosq_gport_discard_set(int unit, bcm_gport_t port, 4140 bcm_cos_queue_t cosq, 4141 bcm_cosq_gport_discard_t *discard) 4142 { 4143 int numq, i; 4144 uint32 min_thresh, max_thresh; 4145 int cell_size, cell_field_max; 4146 bcm_port_t local_port; 4147 bcm_pbmp_t pbmp; 4148 int cosq_start; 4149 int is_64q_port = 0; 4150 4151 if (discard == NULL || 4152 discard->gain < 0 || discard->gain > 15 || 4153 discard->drop_probability < 0 || discard->drop_probability > 100) { 4154 return BCM_E_PARAM; 4155 } 4156 4157 if ((discard->min_thresh < 0) || (discard->max_thresh < 0) || 4158 (discard->min_thresh > discard->max_thresh)) { 4159 return BCM_E_PARAM; 4160 } 4161 4162 cell_size = GH2_BYTES_PER_CELL; 4163 cell_field_max = GH2_CELL_FIELD_MAX; 4164 4165 min_thresh = discard->min_thresh; 4166 max_thresh = discard->max_thresh; 4167 if (discard->flags & BCM_COSQ_DISCARD_BYTES) { 4168 /* Convert bytes to cells */ 4169 min_thresh += (cell_size - 1); 4170 min_thresh /= cell_size; 4171 4172 max_thresh += (cell_size - 1); 4173 max_thresh /= cell_size; 4174 4175 if ((min_thresh > cell_field_max) || 4176 (max_thresh > cell_field_max)) { 4177 return BCM_E_PARAM; 4178 } 4179 } else { /* BCM_COSQ_DISCARD_PACKETS */ 4180 if ((min_thresh > GH2_CELL_FIELD_MAX) || 4181 (max_thresh > GH2_CELL_FIELD_MAX)) { 4182 return BCM_E_PARAM; 4183 } 4184 } 4185 4186 if (BCM_GPORT_IS_SET(port)) { 4187 if (cosq < -1 || cosq >= SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM) { 4188 return BCM_E_PARAM; 4189 } 4190 4191 if (cosq == -1) { 4192 numq = SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM; 4193 cosq_start = 0; 4194 } else { 4195 numq = 1; 4196 cosq_start = cosq; 4197 } 4198 4199 for (i = cosq_start; i < cosq_start+numq; i++) { 4200 BCM_IF_ERROR_RETURN 4201 (bcmi_gh2_cosq_wred_set(unit, port, i, 4202 discard->flags, 4203 min_thresh, max_thresh, 4204 discard->drop_probability, 4205 discard->gain, 4206 FALSE, 0)); 4207 } 4208 } else { 4209 if (port == -1) { 4210 BCM_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit)); 4211 } else if (!SOC_PORT_VALID(unit, port) || 4212 (CMIC_PORT(unit) == port)) { 4213 return BCM_E_PORT; 4214 } else { 4215 BCM_PBMP_PORT_SET(pbmp, port); 4216 } 4217 4218 BCM_PBMP_ITER(pbmp, local_port) { 4219 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port, 4220 &is_64q_port)); 4221 if (is_64q_port) { 4222 if (cosq == -1) { 4223 numq = SOC_GH2_QLAYER_COSQ_PER_PORT_NUM; 4224 cosq_start = 0; 4225 } else { 4226 numq = 1; 4227 cosq_start = cosq; 4228 } 4229 } else { 4230 if (cosq == -1) { 4231 numq = SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM; 4232 cosq_start = 0; 4233 } else { 4234 numq = 1; 4235 cosq_start = cosq; 4236 } 4237 } 4238 4239 for (i = cosq_start; i < cosq_start + numq; i++) { 4240 BCM_IF_ERROR_RETURN 4241 (bcmi_gh2_cosq_wred_set(unit, local_port, i, 4242 discard->flags, 4243 min_thresh, max_thresh, 4244 discard->drop_probability, 4245 discard->gain, 4246 FALSE, 0)); 4247 } 4248 } 4249 } 4250 4251 return BCM_E_NONE; 4252 } 4253 4254 int 4255 bcmi_gh2_cosq_gport_discard_get(int unit, bcm_gport_t port, 4256 bcm_cos_queue_t cosq, 4257 bcm_cosq_gport_discard_t *discard) 4258 { 4259 uint32 min_thresh, max_thresh; 4260 bcm_port_t local_port; 4261 bcm_pbmp_t pbmp; 4262 4263 if (discard == NULL) { 4264 return BCM_E_PARAM; 4265 } 4266 4267 if (BCM_GPORT_IS_SET(port)) { 4268 local_port = port; 4269 } else { 4270 if (port == -1) { 4271 BCM_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit)); 4272 } else if (!SOC_PORT_VALID(unit, port) || 4273 (CMIC_PORT(unit) == port)) { 4274 return BCM_E_PORT; 4275 } else { 4276 /* coverity[overrun-local] */ 4277 BCM_PBMP_PORT_SET(pbmp, port); 4278 } 4279 BCM_PBMP_ITER(pbmp, local_port) { 4280 break; 4281 } 4282 } 4283 4284 if (cosq < -1 || cosq >= gh2_num_cosq[unit]) { 4285 return BCM_E_PARAM; 4286 } 4287 BCM_IF_ERROR_RETURN 4288 (bcmi_gh2_cosq_wred_get(unit, local_port, cosq == -1 ? 0 : cosq, 4289 &discard->flags, &min_thresh, &max_thresh, 4290 &discard->drop_probability, &discard->gain, 0)); 4291 4292 if (discard->flags & BCM_COSQ_DISCARD_BYTES) { 4293 /* Convert number of cells to number of bytes */ 4294 min_thresh *= GH2_BYTES_PER_CELL; 4295 max_thresh *= GH2_BYTES_PER_CELL; 4296 } 4297 discard->min_thresh = min_thresh; 4298 discard->max_thresh = max_thresh; 4299 4300 return BCM_E_NONE; 4301 } 4302 4303 int 4304 bcmi_gh2_cosq_discard_port_set(int unit, bcm_port_t port, 4305 bcm_cos_queue_t cosq, 4306 uint32 color, 4307 int drop_start, 4308 int drop_slope, 4309 int average_time) 4310 { 4311 bcm_port_t local_port; 4312 bcm_pbmp_t pbmp; 4313 int gain; 4314 uint32 min_thresh, max_thresh, n; 4315 uint32 rval, bits; 4316 int numq, i, cosq_start; 4317 4318 int is_64q_port = 0; 4319 int local_cosq; 4320 gh2_cosq_node_t *node = NULL; 4321 4322 if (drop_start < 0 || drop_start > 100 || 4323 drop_slope < 0 || drop_slope > 90) { 4324 return BCM_E_PARAM; 4325 } 4326 4327 /* 4328 * average queue size is reculated every 2us, the formula is 4329 * avg_qsize(t + 1) = 4330 * avg_qsize(t) + (cur_qsize - avg_qsize(t)) / (2 ** gain) 4331 * gain = log2(average_time / 2) 4332 */ 4333 bits = (average_time / gh2_wred_update_interval[unit]) & 0xffff; 4334 if (bits != 0) { 4335 bits |= bits >> 1; 4336 bits |= bits >> 2; 4337 bits |= bits >> 4; 4338 bits |= bits >> 8; 4339 gain = _shr_popcount(bits) - 1; 4340 } else { 4341 gain = 0; 4342 } 4343 4344 if (BCM_GPORT_IS_SET(port)) { 4345 /* 4346 * Paramteres : 4347 * port : gport id, only accept scheduler gport type 4348 * cosq : Valid value 0~7, the input/child id of the gport 4349 * Checked in bcmi_gh2_cosq_wred_set 4350 */ 4351 if (cosq == -1) { 4352 numq = SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM; 4353 cosq_start = 0; 4354 } else { 4355 numq = 1; 4356 cosq_start = cosq; 4357 } 4358 4359 BCM_IF_ERROR_RETURN 4360 (bcmi_gh2_cosq_node_get(unit, port, 0, NULL, 4361 &local_port, NULL, &node)); 4362 4363 for (i = cosq_start; i < (cosq_start + numq); i++) { 4364 /* Get the start point as a function of the HOL limit */ 4365 if (node->node_level == GH2_COSQ_LEVEL_QGROUP) { 4366 if ((i < 0) || (i >= SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM)) { 4367 return BCM_E_PARAM; 4368 } 4369 4370 SOC_IF_ERROR_RETURN 4371 (READ_HOLCOSCELLMAXLIMIT_QGROUPr(unit, local_port, 4372 i, &rval)); 4373 n = soc_reg_field_get(unit, HOLCOSCELLMAXLIMIT_QGROUPr, rval, 4374 CELLMAXLIMITf); 4375 } else if (node->node_level == GH2_COSQ_LEVEL_QLAYER) { 4376 if ((i < 0) || (i >= SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM)) { 4377 return BCM_E_PARAM; 4378 } 4379 /* transfered to hw queue index (0~63) */ 4380 local_cosq = node->qlayer_cosq_min + i; 4381 4382 SOC_IF_ERROR_RETURN 4383 (READ_HOLCOSCELLMAXLIMIT_QLAYERr(unit, local_port, 4384 local_cosq, &rval)); 4385 n = soc_reg_field_get(unit, HOLCOSCELLMAXLIMIT_QLAYERr, rval, 4386 CELLMAXLIMITf); 4387 } else { 4388 /* only accept scheduler gport type */ 4389 return BCM_E_PORT; 4390 } 4391 4392 min_thresh = drop_start * n / 100; 4393 4394 /* Calculate the max threshold. For a given slope (angle in 4395 * degrees), determine how many packets are in the range from 4396 * 0% drop probability to 100% drop probability. Add that 4397 * number to the min_treshold to the the max_threshold. 4398 */ 4399 max_thresh = min_thresh + bcmi_gh2_angle_to_cells(drop_slope); 4400 if (max_thresh > GH2_CELL_FIELD_MAX) { 4401 max_thresh = GH2_CELL_FIELD_MAX; 4402 } 4403 BCM_IF_ERROR_RETURN 4404 (bcmi_gh2_cosq_wred_set(unit, port, i, 4405 (color | BCM_COSQ_DISCARD_TCP), 4406 min_thresh, max_thresh, 100, 4407 gain, TRUE, 0)); 4408 } 4409 } else { 4410 /* 4411 * Paramteres : 4412 * port : local port id 4413 * cosq : Valid value 0~7 or 0~63, depends on MMU port id 4414 * Checked in bcmi_gh2_cosq_wred_set 4415 */ 4416 4417 if (port == -1) { 4418 BCM_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit)); 4419 } else if (!SOC_PORT_VALID(unit, port) || (CMIC_PORT(unit) == port)) { 4420 return BCM_E_PORT; 4421 } else { 4422 BCM_PBMP_PORT_SET(pbmp, port); 4423 } 4424 4425 BCM_PBMP_ITER(pbmp, local_port) { 4426 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port, 4427 &is_64q_port)); 4428 if (is_64q_port) { 4429 if ((cosq < -1) || cosq >= SOC_GH2_2LEVEL_QUEUE_NUM) { 4430 return BCM_E_PARAM; 4431 } 4432 4433 if (cosq == -1) { 4434 numq = SOC_GH2_QLAYER_COSQ_PER_PORT_NUM; 4435 cosq_start = 0; 4436 } else { 4437 numq = 1; 4438 cosq_start = cosq; 4439 } 4440 } else { 4441 if ((cosq < -1) || cosq >= SOC_GH2_LEGACY_QUEUE_NUM) { 4442 return BCM_E_PARAM; 4443 } 4444 4445 if (cosq == -1) { 4446 numq = SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM; 4447 cosq_start = 0; 4448 } else { 4449 numq = 1; 4450 cosq_start = cosq; 4451 } 4452 } 4453 4454 for (i = cosq_start; i < (cosq_start + numq); i++) { 4455 /* Get the start point as a function of the HOL limit */ 4456 if (is_64q_port) { 4457 SOC_IF_ERROR_RETURN 4458 (READ_HOLCOSCELLMAXLIMIT_QLAYERr(unit, local_port, 4459 i, &rval)); 4460 n = soc_reg_field_get(unit, HOLCOSCELLMAXLIMIT_QLAYERr, 4461 rval, CELLMAXLIMITf); 4462 } else { 4463 SOC_IF_ERROR_RETURN 4464 (READ_HOLCOSCELLMAXLIMITr(unit, local_port, i, &rval)); 4465 n = soc_reg_field_get(unit, HOLCOSCELLMAXLIMITr, rval, 4466 CELLMAXLIMITf); 4467 } 4468 4469 min_thresh = drop_start * n / 100; 4470 4471 /* Calculate the max threshold. For a given slope (angle in 4472 * degrees), determine how many packets are in the range from 4473 * 0% drop probability to 100% drop probability. Add that 4474 * number to the min_treshold to the the max_threshold. 4475 */ 4476 max_thresh = min_thresh + bcmi_gh2_angle_to_cells(drop_slope); 4477 if (max_thresh > GH2_CELL_FIELD_MAX) { 4478 max_thresh = GH2_CELL_FIELD_MAX; 4479 } 4480 BCM_IF_ERROR_RETURN 4481 (bcmi_gh2_cosq_wred_set(unit, local_port, i, 4482 (color | BCM_COSQ_DISCARD_TCP), 4483 min_thresh, max_thresh, 100, 4484 gain, TRUE, 0)); 4485 } 4486 } 4487 } 4488 4489 return BCM_E_NONE; 4490 } 4491 4492 int 4493 bcmi_gh2_cosq_discard_port_get(int unit, bcm_port_t port, 4494 bcm_cos_queue_t cosq, 4495 uint32 color, 4496 int *drop_start, 4497 int *drop_slope, 4498 int *average_time) 4499 { 4500 bcm_port_t local_port; 4501 bcm_pbmp_t pbmp; 4502 int gain, drop_prob; 4503 uint32 min_thresh, max_thresh, pkt_limit; 4504 uint32 rval; 4505 int is_64q_port = 0; 4506 int local_cosq; 4507 gh2_cosq_node_t *node = NULL; 4508 4509 if (drop_start == NULL || drop_slope == NULL || average_time == NULL) { 4510 return BCM_E_PARAM; 4511 } 4512 4513 if (BCM_GPORT_IS_SET(port)) { 4514 local_port = port; 4515 } else { 4516 if (port == -1) { 4517 BCM_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit)); 4518 } else if (!SOC_PORT_VALID(unit, port) || (CMIC_PORT(unit) == port)) { 4519 return BCM_E_PORT; 4520 } else { 4521 /* coverity[overrun-local] */ 4522 BCM_PBMP_PORT_SET(pbmp, port); 4523 } 4524 BCM_PBMP_ITER(pbmp, local_port) { 4525 break; 4526 } 4527 } 4528 4529 /* 4530 * Paramteres : checked in bcmi_gh2_cosq_wred_get 4531 * port is gport id, only accept scheduler gport type 4532 * cosq : Valid value 0~7, the input/child id of the gport 4533 * 4534 * port is local port id 4535 * cosq : Valid value 0~7 or 0~63, depends on MMU port id 4536 */ 4537 4538 color |= BCM_COSQ_DISCARD_TCP; 4539 BCM_IF_ERROR_RETURN 4540 (bcmi_gh2_cosq_wred_get(unit, local_port, cosq == -1 ? 0 : cosq, 4541 &color, &min_thresh, &max_thresh, &drop_prob, 4542 &gain, 0)); 4543 4544 /* 4545 * average queue size is reculated every 2(or 1)us, the formula is 4546 * avg_qsize(t + 1) = 4547 * avg_qsize(t) + (cur_qsize - avg_qsize(t)) / (2 ** gain) 4548 */ 4549 *average_time = (1 << gain) * gh2_wred_update_interval[unit]; 4550 4551 /* Get the total HOL limit first */ 4552 if (BCM_GPORT_IS_SET(port)) { 4553 BCM_IF_ERROR_RETURN 4554 (bcmi_gh2_cosq_node_get(unit, port, 0, NULL, 4555 &local_port, NULL, &node)); 4556 if (node->node_level == GH2_COSQ_LEVEL_QGROUP) { 4557 if ((cosq < -1) || (cosq >= SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM)) { 4558 return BCM_E_PARAM; 4559 } 4560 4561 SOC_IF_ERROR_RETURN 4562 (READ_HOLCOSCELLMAXLIMIT_QGROUPr(unit, local_port, 4563 cosq == -1 ? 0 : cosq, &rval)); 4564 4565 pkt_limit = soc_reg_field_get(unit, HOLCOSCELLMAXLIMIT_QGROUPr, 4566 rval, CELLMAXLIMITf); 4567 } else if (node->node_level == GH2_COSQ_LEVEL_QLAYER) { 4568 if ((cosq < -1) || (cosq >= SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM)) { 4569 return BCM_E_PARAM; 4570 } 4571 /* transfered to hw queue index (0~63) */ 4572 local_cosq = node->qlayer_cosq_min + (cosq == -1 ? 0 : cosq); 4573 4574 SOC_IF_ERROR_RETURN 4575 (READ_HOLCOSCELLMAXLIMIT_QLAYERr(unit, local_port, 4576 local_cosq, &rval)); 4577 pkt_limit = soc_reg_field_get(unit, HOLCOSCELLMAXLIMIT_QLAYERr, 4578 rval, CELLMAXLIMITf); 4579 } else { 4580 /* only accept scheduler gport type */ 4581 return BCM_E_PORT; 4582 } 4583 } else { 4584 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port, 4585 &is_64q_port)); 4586 if (is_64q_port) { 4587 if ((cosq < -1) || (cosq >= SOC_GH2_2LEVEL_QUEUE_NUM)) { 4588 return BCM_E_PARAM; 4589 } 4590 BCM_IF_ERROR_RETURN 4591 (READ_HOLCOSCELLMAXLIMIT_QLAYERr(unit, local_port, 4592 cosq == -1 ? 0 : cosq, &rval)); 4593 pkt_limit = soc_reg_field_get(unit, HOLCOSCELLMAXLIMIT_QLAYERr, 4594 rval, CELLMAXLIMITf); 4595 } else { 4596 if ((cosq < -1) || (cosq >= SOC_GH2_LEGACY_QUEUE_NUM)) { 4597 return BCM_E_PARAM; 4598 } 4599 BCM_IF_ERROR_RETURN 4600 (READ_HOLCOSCELLMAXLIMITr(unit, local_port, 4601 cosq == -1 ? 0 : cosq, &rval)); 4602 pkt_limit = soc_reg_field_get(unit, HOLCOSCELLMAXLIMITr, 4603 rval, CELLMAXLIMITf); 4604 } 4605 } 4606 if (min_thresh > pkt_limit) { 4607 min_thresh = pkt_limit; 4608 } 4609 4610 if (max_thresh > pkt_limit) { 4611 max_thresh = pkt_limit; 4612 } 4613 4614 *drop_start = (min_thresh * 100 + pkt_limit - 1) / pkt_limit; 4615 4616 /* Calculate the slope using the min and max threshold. 4617 * The angle is calculated knowing drop probability at min 4618 * threshold is 0% and drop probability at max threshold is 100%. 4619 */ 4620 *drop_slope = bcmi_gh2_cells_to_angle(max_thresh - min_thresh); 4621 return BCM_E_NONE; 4622 } 4623 4624 int 4625 bcmi_gh2_cosq_wred_port_control_set(int unit, 4626 bcm_gport_t gport, 4627 bcm_port_control_t type, 4628 int value) 4629 { 4630 bcm_port_t local_port = 0; 4631 int is_64q_port = 0; 4632 uint32 val = 0; 4633 uint32 fld_val = 0; 4634 int cur_val = 0; 4635 int shift = 0; 4636 gh2_cosq_node_t *node = NULL; 4637 4638 switch (type) { 4639 case bcmPortControlWredDropCountUpdateEnableQueueMask: 4640 /* parameter checking */ 4641 if (value & 0xffffff00) { 4642 /* only 0xff is accepted */ 4643 return BCM_E_PARAM; 4644 } 4645 4646 if (BCM_GPORT_IS_SET(gport)) { 4647 /* To configure 64Q by QLayer scheduler */ 4648 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 4649 return BCM_E_PORT; 4650 } 4651 if (BCM_GPORT_IS_SCHEDULER(gport)) { 4652 BCM_IF_ERROR_RETURN 4653 (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL, 4654 &local_port, NULL, &node)); 4655 if (node->node_level != GH2_COSQ_LEVEL_QLAYER) { 4656 return BCM_E_PORT; 4657 } 4658 4659 if (node->child_idx < 4) { 4660 shift = 8 * node->child_idx; 4661 BCM_IF_ERROR_RETURN( 4662 READ_WRED_DROP_CTR_CONFIG_QLAYER_0r(unit, 4663 local_port, 4664 &val)); 4665 fld_val = \ 4666 soc_reg_field_get(unit, 4667 WRED_DROP_CTR_CONFIG_QLAYER_0r, 4668 val, QUEUE_MASKf); 4669 fld_val &= ~(0xff << shift); 4670 fld_val |= ((value & 0xff) << shift); 4671 soc_reg_field_set(unit, WRED_DROP_CTR_CONFIG_QLAYER_0r, 4672 &val, 4673 QUEUE_MASKf, fld_val); 4674 BCM_IF_ERROR_RETURN( 4675 WRITE_WRED_DROP_CTR_CONFIG_QLAYER_0r(unit, 4676 local_port, 4677 val)); 4678 } else { 4679 shift = 8 * (node->child_idx - 4); 4680 BCM_IF_ERROR_RETURN( 4681 READ_WRED_DROP_CTR_CONFIG_QLAYER_1r(unit, 4682 local_port, 4683 &val)); 4684 fld_val = \ 4685 soc_reg_field_get(unit, 4686 WRED_DROP_CTR_CONFIG_QLAYER_1r, 4687 val, QUEUE_MASKf); 4688 fld_val &= ~(0xff << shift); 4689 fld_val |= ((value & 0xff) << shift); 4690 soc_reg_field_set(unit, WRED_DROP_CTR_CONFIG_QLAYER_1r, 4691 &val, 4692 QUEUE_MASKf, fld_val); 4693 BCM_IF_ERROR_RETURN( 4694 WRITE_WRED_DROP_CTR_CONFIG_QLAYER_1r(unit, 4695 local_port, 4696 val)); 4697 } 4698 } 4699 } else { 4700 /* Legacy COSQ mode, 8 queues per port */ 4701 local_port = gport; 4702 if (!SOC_PORT_VALID(unit, gport)) { 4703 return BCM_E_PORT; 4704 } 4705 4706 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port, 4707 &is_64q_port)); 4708 if (is_64q_port) { 4709 BCM_IF_ERROR_RETURN(soc_reg_field32_modify(unit, 4710 WRED_DROP_CTR_CONFIG_QLAYER_0r, 4711 local_port, QUEUE_MASKf, value)); 4712 } else { 4713 BCM_IF_ERROR_RETURN(soc_reg_field32_modify(unit, 4714 WRED_DROP_CTR_CONFIGr, 4715 local_port, QUEUE_MASKf, value)); 4716 } 4717 } 4718 break; 4719 case bcmPortControlWredDropCountUpdateEnableColorMask: 4720 if (BCM_GPORT_IS_SET(gport)) { 4721 BCM_IF_ERROR_RETURN 4722 (bcm_esw_port_local_get(unit, gport, &local_port)); 4723 } else { 4724 local_port = gport; 4725 if (!SOC_PORT_VALID(unit, local_port)) { 4726 return BCM_E_PORT; 4727 } 4728 } 4729 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port, 4730 &is_64q_port)); 4731 /* parameter checking */ 4732 if (value & ~((0x1 << bcmColorGreen) | 4733 (0x1 << bcmColorYellow) | 4734 (0x1 << bcmColorRed))) { 4735 return BCM_E_PARAM; 4736 } 4737 cur_val = 0; 4738 if (value & (0x1 << bcmColorGreen)) { 4739 cur_val |= 0x4; 4740 } 4741 if (value & (0x1 << bcmColorYellow)) { 4742 cur_val |= 0x2; 4743 } 4744 if (value & (0x1 << bcmColorRed)) { 4745 cur_val |= 0x1; 4746 } 4747 if (is_64q_port) { 4748 BCM_IF_ERROR_RETURN(soc_reg_field32_modify(unit, 4749 WRED_DROP_CTR_CONFIG_COLOR_MASK_QLAYERr, 4750 local_port, COLOR_MASKf, cur_val)); 4751 } else { 4752 BCM_IF_ERROR_RETURN(soc_reg_field32_modify(unit, 4753 WRED_DROP_CTR_CONFIGr, 4754 local_port, COLOR_MASKf, cur_val)); 4755 } 4756 break; 4757 default: 4758 return BCM_E_PARAM; 4759 } 4760 return BCM_E_NONE; 4761 } 4762 4763 int 4764 bcmi_gh2_cosq_wred_port_control_get(int unit, 4765 bcm_gport_t gport, 4766 bcm_port_control_t type, 4767 int *value) 4768 { 4769 bcm_port_t local_port = 0; 4770 int is_64q_port = 0; 4771 uint32 val = 0; 4772 uint32 fld_val = 0; 4773 int shift = 0; 4774 gh2_cosq_node_t *node = NULL; 4775 4776 switch (type) { 4777 case bcmPortControlWredDropCountUpdateEnableQueueMask: 4778 if (BCM_GPORT_IS_SET(gport)) { 4779 /* To configure 64Q by QLayer scheduler */ 4780 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 4781 return BCM_E_PORT; 4782 } 4783 if (BCM_GPORT_IS_SCHEDULER(gport)) { 4784 BCM_IF_ERROR_RETURN 4785 (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL, 4786 &local_port, NULL, &node)); 4787 if (node->node_level != GH2_COSQ_LEVEL_QLAYER) { 4788 return BCM_E_PORT; 4789 } 4790 4791 if (node->child_idx < 4) { 4792 shift = 8 * node->child_idx; 4793 BCM_IF_ERROR_RETURN( 4794 READ_WRED_DROP_CTR_CONFIG_QLAYER_0r(unit, 4795 local_port, 4796 &val)); 4797 fld_val = \ 4798 soc_reg_field_get(unit, 4799 WRED_DROP_CTR_CONFIG_QLAYER_0r, 4800 val, QUEUE_MASKf); 4801 *value = (fld_val >> shift) & 0xff; 4802 } else { 4803 shift = 8 * (node->child_idx - 4); 4804 BCM_IF_ERROR_RETURN( 4805 READ_WRED_DROP_CTR_CONFIG_QLAYER_1r(unit, 4806 local_port, 4807 &val)); 4808 fld_val = 4809 soc_reg_field_get(unit, 4810 WRED_DROP_CTR_CONFIG_QLAYER_1r, 4811 val, QUEUE_MASKf); 4812 *value = (fld_val >> shift) & 0xff; 4813 } 4814 } 4815 } else { 4816 /* Legacy COSQ mode, 8 queues per port */ 4817 local_port = gport; 4818 if (!SOC_PORT_VALID(unit, gport)) { 4819 return BCM_E_PORT; 4820 } 4821 4822 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port, 4823 &is_64q_port)); 4824 if (is_64q_port) { 4825 BCM_IF_ERROR_RETURN( 4826 READ_WRED_DROP_CTR_CONFIG_QLAYER_0r(unit, 4827 local_port, 4828 &val)); 4829 fld_val = soc_reg_field_get(unit, 4830 WRED_DROP_CTR_CONFIG_QLAYER_0r, 4831 val, QUEUE_MASKf); 4832 *value = fld_val & 0xff; 4833 } else { 4834 BCM_IF_ERROR_RETURN( 4835 READ_WRED_DROP_CTR_CONFIGr(unit, local_port, &val)); 4836 fld_val = soc_reg_field_get(unit, WRED_DROP_CTR_CONFIGr, 4837 val, QUEUE_MASKf); 4838 *value = fld_val & 0xff; 4839 } 4840 } 4841 break; 4842 case bcmPortControlWredDropCountUpdateEnableColorMask: 4843 if (BCM_GPORT_IS_SET(gport)) { 4844 BCM_IF_ERROR_RETURN 4845 (bcm_esw_port_local_get(unit, gport, &local_port)); 4846 } else { 4847 local_port = gport; 4848 if (!SOC_PORT_VALID(unit, local_port)) { 4849 return BCM_E_PORT; 4850 } 4851 } 4852 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port, 4853 &is_64q_port)); 4854 if (is_64q_port) { 4855 BCM_IF_ERROR_RETURN( 4856 READ_WRED_DROP_CTR_CONFIG_COLOR_MASK_QLAYERr(unit, 4857 local_port, 4858 &val)); 4859 fld_val = \ 4860 soc_reg_field_get(unit, 4861 WRED_DROP_CTR_CONFIG_COLOR_MASK_QLAYERr, 4862 val, COLOR_MASKf); 4863 } else { 4864 BCM_IF_ERROR_RETURN( 4865 READ_WRED_DROP_CTR_CONFIGr(unit, local_port, &val)); 4866 fld_val = soc_reg_field_get(unit, WRED_DROP_CTR_CONFIGr, 4867 val, COLOR_MASKf); 4868 } 4869 *value = 0; 4870 if (fld_val & 0x4) { 4871 *value |= (0x1 << bcmColorGreen); 4872 } 4873 if (fld_val & 0x2) { 4874 *value |= (0x1 << bcmColorYellow); 4875 } 4876 if (fld_val & 0x1) { 4877 *value |= (0x1 << bcmColorRed); 4878 } 4879 break; 4880 default: 4881 return BCM_E_PARAM; 4882 } 4883 return BCM_E_NONE; 4884 } 4885 4886 /* 4887 * Function: 4888 * bcmi_gh2_cosq_gport_add 4889 * Purpose: 4890 * Create a cosq gport structure 4891 * Parameters: 4892 * unit - (IN) unit number 4893 * port - (IN) port number 4894 * numq - (IN) number of COS queues 4895 * flags - (IN) flags (BCM_COSQ_GPORT_XXX) 4896 * gport - (OUT) GPORT identifier 4897 * Returns: 4898 * BCM_E_XXX 4899 */ 4900 int 4901 bcmi_gh2_cosq_gport_add(int unit, bcm_gport_t port, int numq, uint32 flags, 4902 bcm_gport_t *gport) 4903 { 4904 bcm_port_t local_port; 4905 int phy_port, mmu_port; 4906 uint32 sched_encap; 4907 gh2_mmu_info_t *mmu_info; 4908 gh2_cosq_node_t *node = NULL; 4909 int id; 4910 int is_64q_port; 4911 4912 LOG_INFO(BSL_LS_BCM_COSQ, 4913 (BSL_META_U(unit, 4914 "bcmi_gh2_cosq_gport_add: unit=%d port=0x%x \ 4915 numq=%d flags=0x%x\n"), 4916 unit, port, numq, flags)); 4917 4918 if (gport == NULL) { 4919 return BCM_E_PARAM; 4920 } 4921 4922 if (gh2_mmu_info[unit] == NULL) { 4923 return BCM_E_INIT; 4924 } 4925 4926 BCM_IF_ERROR_RETURN 4927 (bcmi_gh2_cosq_localport_resolve(unit, port, &local_port)); 4928 4929 if (local_port < 0) { 4930 return BCM_E_PORT; 4931 } 4932 4933 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port, 4934 &is_64q_port)); 4935 4936 if (!is_64q_port) { 4937 /* Only MMU port 58-65 support */ 4938 LOG_INFO(BSL_LS_BCM_COSQ, 4939 (BSL_META_U(unit, 4940 "bcmi_gh2_cosq_gport_add: Only MMU port 58-65 support\n"))); 4941 return BCM_E_PORT; 4942 } 4943 4944 mmu_info = gh2_mmu_info[unit]; 4945 4946 switch (flags) { 4947 case BCM_COSQ_GPORT_UCAST_QUEUE_GROUP: 4948 /* to create the gport object of the 64 queues */ 4949 if (numq != 1) { 4950 return BCM_E_PARAM; 4951 } 4952 for (id = 0; 4953 id < GH2_NUM_TOTAL_QUEUES; id++) { 4954 if (mmu_info->queue_node[id].in_use == FALSE) { 4955 node = &mmu_info->queue_node[id]; 4956 node->in_use = TRUE; 4957 break; 4958 } 4959 } 4960 if (!node) { 4961 return BCM_E_RESOURCE; 4962 } 4963 4964 node = &mmu_info->queue_node[id]; 4965 node->node_id = id; 4966 BCM_GPORT_UCAST_QUEUE_GROUP_SYSQID_SET(*gport, local_port, id); 4967 node->node_gport = *gport; 4968 node->node_level = GH2_COSQ_LEVEL_QUEUE; 4969 node->max_num_child = 1; 4970 break; 4971 case BCM_COSQ_GPORT_SCHEDULER: 4972 /* passthru */ 4973 case BCM_COSQ_GPORT_WITH_ID: 4974 case (BCM_COSQ_GPORT_SCHEDULER | BCM_COSQ_GPORT_WITH_ID): 4975 case 0: 4976 if (numq < -1) { 4977 return BCM_E_PARAM; 4978 } 4979 4980 /* 4981 * 80 scheduler nodes, 4982 * the first 8 are for each MMU port 4983 * the others are for QGROUP and QLAYER 4984 */ 4985 if ((flags & BCM_COSQ_GPORT_WITH_ID) || (flags == 0)) { 4986 /* this is a Port level scheduler */ 4987 if (numq > 1) { 4988 LOG_INFO(BSL_LS_BCM_COSQ, 4989 (BSL_META_U(unit, 4990 "bcmi_gh2_cosq_gport_add: \ 4991 only one QGroup scheduler can be \ 4992 attached to egress port\n"))); 4993 return BCM_E_UNAVAIL; 4994 } 4995 4996 phy_port = SOC_INFO(unit).port_l2p_mapping[local_port]; 4997 mmu_port = SOC_INFO(unit).port_p2m_mapping[phy_port]; 4998 id = (mmu_port - SOC_GH2_64Q_MMU_PORT_IDX_MIN); 4999 5000 if ( id < 0 || id >= GH2_NUM_PORT_SCHEDULERS) { 5001 return BCM_E_PARAM; 5002 } 5003 5004 node = &mmu_info->sched_node[id]; 5005 node->node_id = id; 5006 sched_encap = (id << 8) | local_port; 5007 BCM_GPORT_SCHEDULER_SET(*gport, sched_encap); 5008 node->node_gport = *gport; 5009 node->node_level = GH2_COSQ_LEVEL_PORT; 5010 node->max_num_child = 1; 5011 node->in_use = TRUE; 5012 } else { 5013 /* For QGROUP or QLAYER level scheduler */ 5014 if (numq > 8) { 5015 LOG_INFO(BSL_LS_BCM_COSQ, 5016 (BSL_META_U(unit, 5017 "bcmi_gh2_cosq_gport_add: \ 5018 only 8 member scheduler can be \ 5019 attached to QGroup scheduler or \ 5020 QLayer scheduler\n"))); 5021 return BCM_E_UNAVAIL; 5022 } 5023 5024 for (id = GH2_NUM_QGROUP_SCHEDULERS; 5025 id < GH2_NUM_TOTAL_SCHEDULERS; id++) { 5026 if (mmu_info->sched_node[id].in_use == FALSE) { 5027 node = &mmu_info->sched_node[id]; 5028 node->in_use = TRUE; 5029 break; 5030 } 5031 } 5032 if (!node) { 5033 return BCM_E_RESOURCE; 5034 } 5035 5036 node = &mmu_info->sched_node[id]; 5037 node->node_id = id; 5038 sched_encap = (id << 8) | local_port; 5039 BCM_GPORT_SCHEDULER_SET(*gport, sched_encap); 5040 node->node_gport = *gport; 5041 node->max_num_child = numq; 5042 } 5043 break; 5044 5045 default: 5046 return BCM_E_PARAM; 5047 } 5048 5049 LOG_INFO(BSL_LS_BCM_COSQ, 5050 (BSL_META_U(unit, 5051 " gport=0x%x\n"), 5052 *gport)); 5053 5054 return BCM_E_NONE; 5055 } 5056 5057 /* 5058 * Function: 5059 * bcmi_gh2_cosq_gport_delete 5060 * Purpose: 5061 * Destroy a cosq gport structure 5062 * Parameters: 5063 * unit - (IN) unit number 5064 * gport - (IN) GPORT identifier 5065 * Returns: 5066 * BCM_E_XXX 5067 */ 5068 int 5069 bcmi_gh2_cosq_gport_delete(int unit, bcm_gport_t gport) 5070 { 5071 gh2_cosq_node_t *node; 5072 gh2_cosq_node_t *node_child; 5073 int local_port; 5074 int i; 5075 5076 LOG_INFO(BSL_LS_BCM_COSQ, 5077 (BSL_META_U(unit, 5078 "bcmi_gh2_cosq_gport_delete: unit=%d gport=0x%x\n"), 5079 unit, gport)); 5080 5081 if (gh2_mmu_info[unit] == NULL) { 5082 return BCM_E_INIT; 5083 } 5084 5085 node = NULL; 5086 5087 if (!(BCM_GPORT_IS_SCHEDULER(gport) || 5088 BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport))) { 5089 return BCM_E_PORT; 5090 } 5091 5092 BCM_IF_ERROR_RETURN 5093 (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL, 5094 &local_port, NULL, &node)); 5095 5096 if (node == NULL) { 5097 return BCM_E_INTERNAL; 5098 } 5099 5100 if (node->node_level == GH2_COSQ_LEVEL_PORT) { 5101 /* detach child (QGroup) if existed */ 5102 if (node->child_gport[0] != -1) { 5103 BCM_IF_ERROR_RETURN 5104 (bcmi_gh2_cosq_node_get(unit, node->child_gport[0], 5105 0, NULL, NULL, NULL, &node_child)); 5106 BCM_IF_ERROR_RETURN 5107 (bcmi_gh2_cosq_gport_detach(unit, node_child->node_gport, 5108 node->node_gport, 0)); 5109 } 5110 } else if (node->node_level == GH2_COSQ_LEVEL_QGROUP) { 5111 /* detach all child (QLayer) if existed */ 5112 for (i = 0; i < node->num_child; i++) { 5113 if (node->child_gport[i] != -1) { 5114 BCM_IF_ERROR_RETURN 5115 (bcmi_gh2_cosq_node_get(unit, node->child_gport[i], 5116 0, NULL, NULL, NULL, 5117 &node_child)); 5118 BCM_IF_ERROR_RETURN 5119 (bcmi_gh2_cosq_gport_detach(unit, node_child->node_gport, 5120 node->node_gport, 5121 node_child->child_idx)); 5122 } 5123 } 5124 /* detach from parent */ 5125 if (node->parent_gport != -1) { 5126 BCM_IF_ERROR_RETURN 5127 (bcmi_gh2_cosq_gport_detach(unit, node->node_gport, 5128 node->parent_gport, 0)); 5129 } 5130 } else if (node->node_level == GH2_COSQ_LEVEL_QLAYER) { 5131 /* detach all child (QLayer) if existed */ 5132 for (i = 0; i < node->num_child; i++) { 5133 if (node->child_gport[i] != -1) { 5134 BCM_IF_ERROR_RETURN 5135 (bcmi_gh2_cosq_node_get(unit, node->child_gport[i], 5136 0, NULL, NULL, NULL, 5137 &node_child)); 5138 BCM_IF_ERROR_RETURN 5139 (bcmi_gh2_cosq_gport_detach(unit, node_child->node_gport, 5140 node->node_gport, 5141 node_child->child_idx)); 5142 } 5143 } 5144 5145 /* detach parent (QGroup) */ 5146 if (node->parent_gport != -1) { 5147 BCM_IF_ERROR_RETURN 5148 (bcmi_gh2_cosq_gport_detach(unit, node->node_gport, 5149 node->parent_gport, 5150 node->child_idx)); 5151 } 5152 } else { /* GH2_COSQ_LEVEL_QUEUE */ 5153 /* detach parent (QLayer) */ 5154 if (node->parent_gport != -1) { 5155 BCM_IF_ERROR_RETURN 5156 (bcmi_gh2_cosq_gport_detach(unit, node->node_gport, 5157 node->parent_gport, 5158 node->child_idx)); 5159 } 5160 } 5161 /*_BCM_GH2_COSQ_NODE_INIT(node); */ 5162 bcmi_gh2_cosq_node_t_init(node); 5163 return BCM_E_NONE; 5164 } 5165 5166 /* 5167 * Function: 5168 * bcmi_gh2_cosq_gport_traverse 5169 * Purpose: 5170 * Walks through the valid COSQ GPORTs and calls 5171 * the user supplied callback function for each entry. 5172 * Parameters: 5173 * unit - (IN) unit number 5174 * trav_fn - (IN) Callback function. 5175 * user_data - (IN) User data to be passed to callback function 5176 * Returns: 5177 * BCM_E_NONE - Success. 5178 * BCM_E_XXX 5179 */ 5180 int 5181 bcmi_gh2_cosq_gport_traverse(int unit, bcm_cosq_gport_traverse_cb cb, 5182 void *user_data) 5183 { 5184 gh2_mmu_info_t *mmu_info; 5185 gh2_cosq_node_t *node; 5186 uint32 flags = BCM_COSQ_GPORT_SCHEDULER; 5187 int rv = BCM_E_NONE; 5188 int i; 5189 int numq; 5190 5191 if (gh2_mmu_info[unit] == NULL) { 5192 return BCM_E_INIT; 5193 } 5194 mmu_info = gh2_mmu_info[unit]; 5195 5196 for (i = 0 ; i < GH2_NUM_TOTAL_SCHEDULERS; i++) { 5197 node = &mmu_info->sched_node[i]; 5198 if (node->in_use) { 5199 flags = BCM_COSQ_GPORT_SCHEDULER; 5200 if (node->node_level == GH2_COSQ_LEVEL_PORT) { 5201 numq = 1; 5202 } else if (node->node_level == GH2_COSQ_LEVEL_QGROUP) { 5203 numq = node->num_child; 5204 } else { /* GH2_COSQ_LEVEL_QLAYER */ 5205 numq = 8; 5206 } 5207 rv = cb(unit, node->node_gport, numq, flags, 5208 node->node_gport, user_data); 5209 if (BCM_FAILURE(rv)) { 5210 #ifdef BCM_CB_ABORT_ON_ERR 5211 if (SOC_CB_ABORT_ON_ERR(unit)) { 5212 return rv; 5213 } 5214 #endif 5215 } 5216 } 5217 } 5218 5219 for (i = 0 ; i < GH2_NUM_TOTAL_QUEUES; i++) { 5220 node = &mmu_info->queue_node[i]; 5221 if (node->in_use) { 5222 flags = BCM_COSQ_GPORT_UCAST_QUEUE_GROUP; 5223 numq = 1; 5224 rv = cb(unit, node->node_gport, numq, flags, 5225 node->node_gport, user_data); 5226 if (BCM_FAILURE(rv)) { 5227 #ifdef BCM_CB_ABORT_ON_ERR 5228 if (SOC_CB_ABORT_ON_ERR(unit)) { 5229 return rv; 5230 } 5231 #endif 5232 } 5233 } 5234 } 5235 return BCM_E_NONE; 5236 } 5237 5238 /* 5239 * Function: 5240 * bcmi_gh2_cosq_gport_get 5241 * Purpose: 5242 * Get a cosq gport structure 5243 * Parameters: 5244 * unit - (IN) unit number 5245 * gport - (IN) GPORT identifier 5246 * port - (OUT) port number 5247 * numq - (OUT) number of COS queues 5248 * flags - (OUT) flags (BCM_COSQ_GPORT_XXX) 5249 * Returns: 5250 * BCM_E_XXX 5251 */ 5252 int 5253 bcmi_gh2_cosq_gport_get(int unit, bcm_gport_t gport, bcm_gport_t *port, 5254 int *numq, uint32 *flags) 5255 { 5256 gh2_cosq_node_t *node = NULL; 5257 bcm_module_t modid; 5258 bcm_port_t local_port; 5259 int id; 5260 _bcm_gport_dest_t dest; 5261 5262 if (gh2_mmu_info[unit] == NULL) { 5263 return BCM_E_INIT; 5264 } 5265 5266 if (port == NULL || numq == NULL || flags == NULL) { 5267 return BCM_E_PARAM; 5268 } 5269 5270 LOG_INFO(BSL_LS_BCM_COSQ, 5271 (BSL_META_U(unit, 5272 "bcmi_gh2_cosq_gport_get: unit=%d gport=0x%x\n"), 5273 unit, gport)); 5274 5275 if (!(BCM_GPORT_IS_SCHEDULER(gport) || 5276 BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport))) { 5277 return BCM_E_PORT; 5278 } 5279 5280 BCM_IF_ERROR_RETURN 5281 (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL, &local_port, &id, &node)); 5282 5283 if (SOC_USE_GPORT(unit)) { 5284 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &modid)); 5285 dest.gport_type = _SHR_GPORT_TYPE_MODPORT; 5286 dest.modid = modid; 5287 dest.port = local_port; 5288 BCM_IF_ERROR_RETURN(_bcm_esw_gport_construct(unit, &dest, port)); 5289 } else { 5290 *port = local_port; 5291 } 5292 5293 if (node->node_level == GH2_COSQ_LEVEL_PORT) { 5294 *flags = 0; 5295 } else if (node->node_level == GH2_COSQ_LEVEL_QUEUE) { 5296 *flags = BCM_COSQ_GPORT_UCAST_QUEUE_GROUP; 5297 } else { /* GH2_COSQ_LEVEL_QGROUP or GH2_COSQ_LEVEL_QLAYER */ 5298 *flags = BCM_COSQ_GPORT_SCHEDULER; 5299 } 5300 *numq = node->max_num_child; 5301 5302 LOG_INFO(BSL_LS_BCM_COSQ, 5303 (BSL_META_U(unit, 5304 " port=0x%x numq=%d flags=0x%x\n"), 5305 *port, *numq, *flags)); 5306 5307 return BCM_E_NONE; 5308 } 5309 5310 /* 5311 * Function: 5312 * bcmi_gh2_cosq_gport_attach 5313 * Purpose: 5314 * Attach sched_port to the specified index (cosq) of input_port 5315 * Parameters: 5316 * unit - (IN) unit number 5317 * sched_port - (IN) scheduler GPORT identifier 5318 * input_port - (IN) GPORT to attach to 5319 * cosq - (IN) COS queue to attach to (-1 for first available cosq) 5320 * Returns: 5321 * BCM_E_XXX 5322 */ 5323 int 5324 bcmi_gh2_cosq_gport_attach(int unit, bcm_gport_t gport, 5325 bcm_gport_t to_gport, 5326 bcm_cos_queue_t to_cosq) 5327 { 5328 gh2_cosq_node_t *node, *to_node, *temp_node; 5329 bcm_port_t port, to_port; 5330 int i; 5331 int child_index = 0; 5332 uint32 reg_val = 0; 5333 int id; 5334 int phy_port, mmu_port; 5335 gh2_mmu_info_t *mmu_info; 5336 5337 5338 if (gh2_mmu_info[unit] == NULL) { 5339 return BCM_E_INIT; 5340 } 5341 5342 /* 5343 * Three kinds of attach supported 5344 * 1.QGROUP scheduler(gport) attaches to egress port(to_gport) 5345 * egress port(to_gport) here can be local port id or gport id 5346 * 2.QLAYER scheduler(gport) attaches to QGROUP scheduler(to_gport) 5347 * 3.Queue node(gport) attaches to QLAYER scheduler(to_gport) 5348 */ 5349 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(to_gport)) { 5350 return BCM_E_PARAM; 5351 } 5352 5353 if (!(BCM_GPORT_IS_SCHEDULER(to_gport) || 5354 BCM_GPORT_IS_LOCAL(to_gport) || 5355 BCM_GPORT_IS_MODPORT(to_gport))) { 5356 return BCM_E_PORT; 5357 } 5358 5359 if (!(BCM_GPORT_IS_SCHEDULER(gport) || 5360 BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport))) { 5361 return BCM_E_PORT; 5362 } 5363 5364 if (to_cosq < -1) { 5365 return BCM_E_PARAM; 5366 } 5367 5368 to_node = NULL; 5369 if (BCM_GPORT_IS_SCHEDULER(to_gport)) { 5370 /* 5371 * attach cases : 5372 * 1.QGROUP scheduler(gport) attaches to egress port(to_gport) 5373 * 2.QLAYER scheduler(gport) attaches to QGROUP scheduler(to_gport) 5374 * 3.Queue node(gport) attaches to QLAYER scheduler(to_gport) 5375 */ 5376 BCM_IF_ERROR_RETURN 5377 (bcmi_gh2_cosq_node_get(unit, to_gport, 0, NULL, &to_port, NULL, 5378 &to_node)); 5379 } else { 5380 /* to_gport is local port */ 5381 5382 /* QGROUP scheduler(gport) attaches to egress port(to_gport) */ 5383 BCM_IF_ERROR_RETURN 5384 (bcmi_gh2_cosq_localport_resolve(unit, to_gport, &to_port)); 5385 5386 /* Does it ever created PORT scheduler?*/ 5387 phy_port = SOC_INFO(unit).port_l2p_mapping[to_port]; 5388 mmu_port = SOC_INFO(unit).port_p2m_mapping[phy_port]; 5389 id = (mmu_port - SOC_GH2_64Q_MMU_PORT_IDX_MIN); 5390 5391 if ( id < 0 || id >= GH2_NUM_PORT_SCHEDULERS) { 5392 return BCM_E_PARAM; 5393 } 5394 5395 mmu_info = gh2_mmu_info[unit]; 5396 temp_node = &mmu_info->sched_node[id]; 5397 if (temp_node->in_use) { 5398 to_node = temp_node; 5399 } 5400 } 5401 5402 if (to_node != NULL) { 5403 if (to_node->node_level == GH2_COSQ_LEVEL_PORT) { 5404 /* only 1 QGROUP scheduler can be attached to egress port(gport) */ 5405 if (to_cosq >= 1) { 5406 return BCM_E_PARAM; 5407 } 5408 } else { 5409 /* 5410 * Only 8 QLAYER scheduler can be attached to QGROUP scheduler 5411 * Or, only 8 queue can be attached to QLAYER scheduler 5412 */ 5413 if (to_cosq >= 8) { 5414 return BCM_E_PARAM; 5415 } 5416 } 5417 } else { 5418 /* only 1 QGROUP scheduler can be attached to egress port(gport) */ 5419 if (to_cosq >= 1) { 5420 return BCM_E_PARAM; 5421 } 5422 } 5423 5424 BCM_IF_ERROR_RETURN 5425 (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL, &port, NULL, &node)); 5426 5427 if (port != to_port) { 5428 return BCM_E_PORT; 5429 } 5430 5431 if (node->parent_gport != -1) { 5432 /* Has already attached */ 5433 return BCM_E_EXISTS; 5434 } 5435 5436 if (to_node != NULL) { 5437 if (to_node->node_level == GH2_COSQ_LEVEL_PORT) { 5438 /* QGROUP scheduler(gport) attaches to egress port(to_gport) */ 5439 to_node->child_gport[0] = gport; 5440 to_node->num_child = 1; 5441 5442 node->parent_gport = to_gport; 5443 node->node_level = GH2_COSQ_LEVEL_QGROUP; 5444 5445 /* enable two layer scheduler mode */ 5446 READ_TWO_LAYER_SCH_MODEr(unit, to_port, ®_val); 5447 soc_reg_field_set(unit, TWO_LAYER_SCH_MODEr, ®_val, 5448 SCH_MODEf, 1); 5449 WRITE_TWO_LAYER_SCH_MODEr(unit, to_port, reg_val); 5450 } else { 5451 /* QLAYER scheduler(gport) attaches to QGROUP scheduler(to_gport) 5452 * or 5453 * Queue node(gport) attaches to QLAYER scheduler(to_gport) 5454 */ 5455 if (to_cosq == -1) { 5456 /* find the first available index */ 5457 for (i = 0; i < to_node->max_num_child; i++) { 5458 if (to_node->child_gport[i] != BCM_GPORT_INVALID) { 5459 child_index = i; 5460 } 5461 } 5462 } else { 5463 child_index = to_cosq; 5464 } 5465 5466 to_node->child_gport[child_index] = gport; 5467 to_node->num_child++; 5468 node->parent_gport = to_gport; 5469 node->child_idx = child_index; 5470 if (to_node->node_level == GH2_COSQ_LEVEL_QGROUP) { 5471 node->node_level = GH2_COSQ_LEVEL_QLAYER; 5472 node->qlayer_cosq_min = (child_index * 8); 5473 node->qlayer_cosq_max = ((child_index + 1) * 8) -1; 5474 } 5475 } 5476 } else { 5477 /* QGROUP scheduler(gport) attaches to egress port(to_gport) */ 5478 node->parent_gport = to_gport; 5479 node->node_level = GH2_COSQ_LEVEL_QGROUP; 5480 5481 /* enable two layer scheduler mode */ 5482 READ_TWO_LAYER_SCH_MODEr(unit, to_port, ®_val); 5483 soc_reg_field_set(unit, TWO_LAYER_SCH_MODEr, ®_val, 5484 SCH_MODEf, 1); 5485 WRITE_TWO_LAYER_SCH_MODEr(unit, to_port, reg_val); 5486 } 5487 5488 return BCM_E_NONE; 5489 } 5490 5491 /* 5492 * Function: 5493 * bcmi_gh2_cosq_gport_attach_get 5494 * Purpose: 5495 * Get attached status of a scheduler port 5496 * Parameters: 5497 * unit - (IN) unit number 5498 * gport - (IN) scheduler GPORT identifier 5499 * input_gport - (OUT) GPORT to attach to 5500 * cosq - (OUT) COS queue to attached to 5501 * Returns: 5502 * BCM_E_XXX 5503 * Notes: 5504 */ 5505 int 5506 bcmi_gh2_cosq_gport_attach_get(int unit, bcm_gport_t gport, 5507 bcm_gport_t *input_gport, bcm_cos_queue_t *cosq) 5508 { 5509 gh2_cosq_node_t *node; 5510 bcm_module_t modid; 5511 bcm_port_t port; 5512 5513 if (gh2_mmu_info[unit] == NULL) { 5514 return BCM_E_INIT; 5515 } 5516 5517 if (input_gport == NULL || cosq == NULL) { 5518 return BCM_E_PARAM; 5519 } 5520 5521 BCM_IF_ERROR_RETURN 5522 (bcmi_gh2_cosq_node_get(unit, gport, 0, &modid, &port, NULL, 5523 &node)); 5524 5525 if (node->parent_gport == -1) { 5526 /* Not attached yet */ 5527 return BCM_E_NOT_FOUND; 5528 } 5529 5530 if (node->node_level == GH2_COSQ_LEVEL_PORT) { 5531 /* PORT level scheduler has no parent */ 5532 return BCM_E_PORT; 5533 } else if (node->node_level == GH2_COSQ_LEVEL_QGROUP) { 5534 *cosq = 0; 5535 } else { 5536 /* GH2_COSQ_LEVEL_QLAYER or GH2_COSQ_LEVEL_QUEUE */ 5537 *cosq = node->child_idx; 5538 } 5539 *input_gport = node->parent_gport; 5540 5541 return BCM_E_NONE; 5542 } 5543 5544 /* 5545 * Function: 5546 * bcmi_gh2_cosq_gport_child_get 5547 * Purpose: 5548 * Get the child node GPORT atatched to N-th index (cosq) 5549 * of the scheduler GPORT. 5550 * Parameters: 5551 * unit - (IN) Unit number. 5552 * in_gport - (IN) Scheduler GPORT ID. 5553 * cosq - (IN) COS queue attached to. 5554 * out_gport - (OUT) child GPORT ID. 5555 * Returns: 5556 * BCM_E_XXX 5557 * Notes: 5558 */ 5559 int 5560 bcmi_gh2_cosq_gport_child_get(int unit, bcm_gport_t in_gport, 5561 bcm_cos_queue_t cosq, 5562 bcm_gport_t *out_gport) 5563 { 5564 gh2_cosq_node_t *in_node = NULL; 5565 bcm_module_t in_modid = 0; 5566 bcm_port_t in_port = -1; 5567 int phy_port, mmu_port; 5568 int id; 5569 gh2_mmu_info_t *mmu_info; 5570 5571 if (gh2_mmu_info[unit] == NULL) { 5572 return BCM_E_INIT; 5573 } 5574 mmu_info = gh2_mmu_info[unit]; 5575 5576 if (out_gport == NULL) { 5577 return BCM_E_PARAM; 5578 } 5579 5580 if (BCM_GPORT_IS_SET(in_gport) && !BCM_GPORT_IS_SCHEDULER(in_gport)) { 5581 return BCM_E_PORT; 5582 } 5583 5584 if (cosq < 0) { 5585 return BCM_E_PARAM; 5586 } 5587 5588 if (!BCM_GPORT_IS_SET(in_gport)) { 5589 /* this is a PORT level scheduler */ 5590 /* only 1 QGROUP scheduler can be attached to egress port */ 5591 if (cosq >= 64) { 5592 return BCM_E_PARAM; 5593 } 5594 if (cosq >= 1) { 5595 return BCM_E_NOT_FOUND; 5596 } 5597 5598 BCM_IF_ERROR_RETURN 5599 (bcmi_gh2_cosq_localport_resolve(unit, in_gport, &in_port)); 5600 phy_port = SOC_INFO(unit).port_l2p_mapping[in_port]; 5601 mmu_port = SOC_INFO(unit).port_p2m_mapping[phy_port]; 5602 id = (mmu_port - SOC_GH2_64Q_MMU_PORT_IDX_MIN); 5603 5604 if ( id < 0 || id >= GH2_NUM_PORT_SCHEDULERS) { 5605 return BCM_E_PARAM; 5606 } 5607 in_node = &mmu_info->sched_node[id]; 5608 if (in_node->in_use) { 5609 /* The child gport is not valid (not attached) */ 5610 if (BCM_GPORT_INVALID == in_node->child_gport[0]) { 5611 return BCM_E_NOT_FOUND; 5612 } 5613 *out_gport =in_node->child_gport[0]; 5614 } else { 5615 return BCM_E_NOT_FOUND; 5616 } 5617 } else { 5618 BCM_IF_ERROR_RETURN 5619 (bcmi_gh2_cosq_node_get(unit, in_gport, 0, &in_modid, &in_port, 5620 NULL, &in_node)); 5621 if (in_node->node_level == GH2_COSQ_LEVEL_PORT) { 5622 /* this is a PORT level scheduler */ 5623 /* only 1 QGROUP scheduler can be attached to egress port */ 5624 if (cosq >= 64) { 5625 return BCM_E_PARAM; 5626 } 5627 if (cosq >= 1) { 5628 return BCM_E_NOT_FOUND; 5629 } 5630 } else { 5631 if (cosq >= 8) { 5632 return BCM_E_PARAM; 5633 } 5634 } 5635 5636 if (in_node->node_level == GH2_COSQ_LEVEL_QUEUE) { 5637 /* no child will be attached to the queue node */ 5638 return BCM_E_PARAM; 5639 } 5640 5641 /* The child gport is not valid (not attached) */ 5642 if (BCM_GPORT_INVALID == in_node->child_gport[cosq]) { 5643 return BCM_E_NOT_FOUND; 5644 } 5645 5646 /* Get the child gport */ 5647 *out_gport = in_node->child_gport[cosq]; 5648 } 5649 5650 return BCM_E_NONE; 5651 } 5652 5653 5654 /* 5655 * Function: 5656 * bcmi_gh2_cosq_gport_detach 5657 * Purpose: 5658 * Detach sched_port from the specified index (cosq) of input_port 5659 * Parameters: 5660 * unit - (IN) unit number 5661 * gport - (IN) scheduler GPORT identifier 5662 * input_gport - (IN) GPORT to detach from 5663 * cosq - (IN) COS queue to detach from 5664 * Returns: 5665 * BCM_E_XXX 5666 */ 5667 int 5668 bcmi_gh2_cosq_gport_detach(int unit, bcm_gport_t gport, 5669 bcm_gport_t input_gport, bcm_cos_queue_t cosq) 5670 { 5671 gh2_cosq_node_t *node, *input_node = NULL, *temp_node = NULL; 5672 bcm_port_t port, input_port = -1; 5673 int child_index; 5674 uint32 reg_val; 5675 int id; 5676 int phy_port, mmu_port; 5677 gh2_mmu_info_t *mmu_info; 5678 5679 if (gh2_mmu_info[unit] == NULL) { 5680 return BCM_E_INIT; 5681 } 5682 5683 /* 5684 * Three kinds of attach/detach supported 5685 * 1.QGROUP scheduler(gport) attached to egress port(input_gport) 5686 * 2.QLAYER scheduler(gport) attached to QGROUP scheduler(input_gport) 5687 * 3.Queue node(gport) attached to QLAYER scheduler(input_gport) 5688 */ 5689 if (!(BCM_GPORT_IS_SCHEDULER(input_gport) || 5690 BCM_GPORT_IS_MODPORT(input_gport) || 5691 BCM_GPORT_IS_LOCAL(input_gport))) { 5692 return BCM_E_PARAM; 5693 } 5694 if (!(BCM_GPORT_IS_SCHEDULER(gport) || 5695 BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport))) { 5696 return BCM_E_PORT; 5697 } 5698 5699 if (cosq < -1) { 5700 return BCM_E_PARAM; 5701 } 5702 5703 input_node = NULL; 5704 if (BCM_GPORT_IS_SCHEDULER(input_gport)) { 5705 /* 5706 * attached cases : 5707 * 1.QLAYER scheduler(gport) attached to QGROUP scheduler(input_gport) 5708 * 2.QGROUP scheduler(gport) attached to egress port(input_gport) 5709 * 3.Queue node(gport) attached to QLAYER scheduler(input_gport) 5710 */ 5711 BCM_IF_ERROR_RETURN 5712 (bcmi_gh2_cosq_node_get(unit, input_gport, 0, NULL, &input_port, 5713 NULL, &input_node)); 5714 } else { 5715 /* input_gport is local port */ 5716 5717 /* QGROUP scheduler(gport) attached from egress port(input_gport) */ 5718 BCM_IF_ERROR_RETURN 5719 (bcmi_gh2_cosq_localport_resolve(unit, input_gport, &input_port)); 5720 5721 /* Does it ever created PORT scheduler?*/ 5722 phy_port = SOC_INFO(unit).port_l2p_mapping[input_port]; 5723 mmu_port = SOC_INFO(unit).port_p2m_mapping[phy_port]; 5724 id = (mmu_port - SOC_GH2_64Q_MMU_PORT_IDX_MIN); 5725 5726 if ( id < 0 || id >= GH2_NUM_PORT_SCHEDULERS) { 5727 return BCM_E_PARAM; 5728 } 5729 5730 mmu_info = gh2_mmu_info[unit]; 5731 temp_node = &mmu_info->sched_node[id]; 5732 if (temp_node->in_use) { 5733 input_node = temp_node; 5734 } 5735 } 5736 5737 if (input_node != NULL) { 5738 if (input_node->node_level == GH2_COSQ_LEVEL_PORT) { 5739 /* only 1 QGROUP scheduler can be attached to egress port(gport) */ 5740 if (cosq >= 1) { 5741 return BCM_E_PARAM; 5742 } 5743 } else { 5744 /* only 8 QLAYER scheduler can be attached to QGROUP scheduler */ 5745 /* only 8 QLAYER scheduler can be attached to QGROUP scheduler */ 5746 if (cosq >= 8) { 5747 return BCM_E_PARAM; 5748 } 5749 } 5750 } else { 5751 /* only 1 QGROUP scheduler can be attached to egress port(gport) */ 5752 if (cosq >= 1) { 5753 return BCM_E_PARAM; 5754 } 5755 } 5756 5757 BCM_IF_ERROR_RETURN 5758 (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL, &port, NULL, 5759 &node)); 5760 5761 if (port != input_port) { 5762 return BCM_E_PORT; 5763 } 5764 if (node->parent_gport == -1) { 5765 /* Not attached yet */ 5766 return BCM_E_NOT_FOUND; 5767 } 5768 5769 if (input_node != NULL) { 5770 if (input_node->node_level == GH2_COSQ_LEVEL_PORT) { 5771 /* 5772 * QGROUP scheduler(gport) detaches from 5773 * PORT scheduler(input_gport) 5774 */ 5775 input_node->child_gport[0] = BCM_GPORT_INVALID; 5776 input_node->num_child--; 5777 node->parent_gport = -1; 5778 node->child_idx = -1; 5779 node->qlayer_cosq_min = -1; 5780 node->qlayer_cosq_max = -1; 5781 5782 /* disable two layer scheduler mode */ 5783 READ_TWO_LAYER_SCH_MODEr(unit, input_port, ®_val); 5784 soc_reg_field_set(unit, TWO_LAYER_SCH_MODEr, ®_val, 5785 SCH_MODEf, 0); 5786 WRITE_TWO_LAYER_SCH_MODEr(unit, input_port, reg_val); 5787 } else { 5788 /* QLAYER scheduler(gport) detaches from QGROUP scheduler(to_gport) 5789 * or 5790 * Queue node(gport) detaches from QLAYER scheduler(to_gport) 5791 */ 5792 if (cosq == -1) { 5793 /* not specified, just get input node */ 5794 child_index = node->child_idx; 5795 } else { 5796 /* detach cosq is not the same as recorded */ 5797 if (node->child_idx != cosq) { 5798 return BCM_E_PARAM; 5799 } 5800 child_index = cosq; 5801 } 5802 5803 input_node->child_gport[child_index] = BCM_GPORT_INVALID; 5804 input_node->num_child--; 5805 node->parent_gport = -1; 5806 node->child_idx = -1; 5807 node->qlayer_cosq_min = -1; 5808 node->qlayer_cosq_max = -1; 5809 } 5810 } else { 5811 /* QGROUP scheduler(gport) detaches from egress port(input_gport) */ 5812 node->parent_gport = -1; 5813 5814 /* disable two layer scheduler mode */ 5815 READ_TWO_LAYER_SCH_MODEr(unit, input_port, ®_val); 5816 soc_reg_field_set(unit, TWO_LAYER_SCH_MODEr, ®_val, 5817 SCH_MODEf, 0); 5818 WRITE_TWO_LAYER_SCH_MODEr(unit, input_port, reg_val); 5819 } 5820 return BCM_E_NONE; 5821 } 5822 #ifndef BCM_SW_STATE_DUMP_DISABLE 5823 static void 5824 bcmi_gh2_gport_scheduler_dump(int unit, bcm_gport_t port) 5825 { 5826 int rv; 5827 bcm_gport_t lvl0 = BCM_GPORT_INVALID; 5828 bcm_gport_t lvl1 = BCM_GPORT_INVALID; 5829 bcm_gport_t lvl2[8]; 5830 int i, j; 5831 5832 /* Get LVL0 scheduler */ 5833 rv = bcmi_gh2_cosq_gport_child_get(unit, port, 0, &lvl0); 5834 if (BCM_FAILURE(rv)) { 5835 return; 5836 } 5837 5838 LOG_CLI((BSL_META_U(unit, 5839 " Port : %d\n"), 5840 port)); 5841 LOG_CLI((BSL_META_U(unit, 5842 " LVL-0 scheduler : 0x%x\n"), 5843 lvl0)); 5844 for (i = 0; i < 8; i++) { 5845 rv = bcmi_gh2_cosq_gport_child_get(unit, lvl0, i, &lvl1); 5846 if (BCM_FAILURE(rv)) { 5847 continue; 5848 } 5849 LOG_CLI((BSL_META_U(unit, 5850 " LVL-1 scheduler : 0x%x\n"), 5851 lvl1)); 5852 LOG_CLI((BSL_META_U(unit, 5853 " LVL-2 queues : "))); 5854 for (j = 0; j < 8; j++) { 5855 lvl2[j] = BCM_GPORT_INVALID; 5856 rv = bcmi_gh2_cosq_gport_child_get(unit, lvl1, j, &lvl2[j]); 5857 if (BCM_SUCCESS(rv)) { 5858 LOG_CLI((BSL_META_U(unit, 5859 "0x%x "), 5860 lvl2[j])); 5861 } 5862 } 5863 LOG_CLI((BSL_META_U(unit, 5864 "\n"))); 5865 } 5866 5867 return; 5868 } 5869 5870 /* 5871 * Function: 5872 * bcmi_gh2_cosq_sw_dump 5873 * Purpose: 5874 * Displays COS Queue information maintained by software. 5875 * Parameters: 5876 * unit - Device unit number 5877 * Returns: 5878 * None 5879 */ 5880 void 5881 bcmi_gh2_cosq_sw_dump(int unit) 5882 { 5883 int i; 5884 5885 LOG_CLI((BSL_META_U(unit, 5886 "\nSW Information COSQ - Unit %d\n"), unit)); 5887 5888 /* Number COSQ */ 5889 LOG_CLI((BSL_META_U(unit, 5890 " Number: %d\n"), gh2_num_cosq[unit])); 5891 5892 if (gh2_mmu_info[unit]) { 5893 bcm_pbmp_t ports; 5894 bcm_port_t port; 5895 int is_64q_port = 0; 5896 int rv = 0; 5897 5898 BCM_PBMP_ASSIGN(ports, PBMP_ALL(unit)); 5899 PBMP_ITER(ports, port) { 5900 rv = soc_gh2_64q_port_check(unit, port, &is_64q_port); 5901 if (SOC_SUCCESS(rv) && is_64q_port) { 5902 bcmi_gh2_gport_scheduler_dump(unit, port); 5903 } 5904 } 5905 } 5906 5907 /* COSQ Map profile */ 5908 /* Display those entries with reference count > 0 */ 5909 LOG_CLI((BSL_META_U(unit, 5910 " COSQ Map Profile:\n"))); 5911 if (gh2_cos_map_profile[unit] != NULL) { 5912 int num_entries; 5913 int ref_count; 5914 int entries_per_set; 5915 uint32 index; 5916 port_cos_map_entry_t *entry_p; 5917 uint32 cosq, hg_cosq; 5918 5919 num_entries = soc_mem_index_count 5920 (unit, gh2_cos_map_profile[unit]->tables[0].mem); 5921 LOG_CLI((BSL_META_U(unit, 5922 " Number of entries: %d\n"), num_entries)); 5923 LOG_CLI((BSL_META_U(unit, 5924 " Index RefCount EntriesPerSet - " 5925 "COS HG_COS\n"))); 5926 5927 for (index = 0; index < num_entries; 5928 index += GH2_COS_MAP_ENTRIES_PER_SET) { 5929 if (SOC_FAILURE 5930 (soc_profile_mem_ref_count_get(unit, 5931 gh2_cos_map_profile[unit], 5932 index, &ref_count))) { 5933 break; 5934 } 5935 5936 if (ref_count <= 0) { 5937 continue; 5938 } 5939 5940 for (i = 0; i < GH2_COS_MAP_ENTRIES_PER_SET; i++) { 5941 entries_per_set = 5942 gh2_cos_map_profile[unit]->tables[0]. 5943 entries[index + i].entries_per_set; 5944 LOG_CLI((BSL_META_U(unit, 5945 " %5d %8d %13d "), 5946 index + i, ref_count, entries_per_set)); 5947 5948 entry_p = SOC_PROFILE_MEM_ENTRY(unit, 5949 gh2_cos_map_profile[unit], 5950 port_cos_map_entry_t *, 5951 index + i); 5952 cosq = soc_mem_field32_get(unit, 5953 PORT_COS_MAPm, 5954 entry_p, 5955 COSf); 5956 LOG_CLI((BSL_META_U(unit, 5957 "%2d "), cosq)); 5958 if (soc_mem_field_valid(unit, PORT_COS_MAPm, HG_COSf)) { 5959 hg_cosq = soc_mem_field32_get(unit, PORT_COS_MAPm, 5960 entry_p, 5961 HG_COSf); 5962 LOG_CLI((BSL_META_U(unit, 5963 " %2d"), hg_cosq)); 5964 } 5965 LOG_CLI((BSL_META_U(unit, 5966 "\n"))); 5967 } 5968 } 5969 } 5970 5971 return; 5972 } 5973 #endif /*BCM_SW_STATE_DUMP_DISABLE */ 5974 5975 5976 /* 5977 * Function: 5978 * bcmi_gh2_cosq_drop_status_enable_set 5979 * Purpose: 5980 * Program E2ECC mode 5981 * Parameters: 5982 * unit - (IN) Unit number. 5983 * port - (IN) port ID 5984 * enable- (IN) enable or disable. 5985 * Returns: 5986 * BCM_E_xxx 5987 * Notes: 5988 */ 5989 int 5990 bcmi_gh2_cosq_drop_status_enable_set(int unit, bcm_port_t port, int enable) 5991 { 5992 uint32 rval; 5993 bcm_port_t local_port; 5994 int is_64q; 5995 5996 COMPILER_REFERENCE(port); 5997 PBMP_E_ITER (unit, local_port) { 5998 BCM_IF_ERROR_RETURN(READ_E2ECC_PORT_CONFIGr(unit, local_port, &rval)); 5999 soc_reg_field_set(unit, E2ECC_PORT_CONFIGr, &rval, 6000 COS_CELL_ENf, enable ? 0xFF : 0x0); 6001 soc_reg_field_set(unit, E2ECC_PORT_CONFIGr, &rval, 6002 COS_PKT_ENf, enable ? 0xFF : 0x0); 6003 BCM_IF_ERROR_RETURN(WRITE_E2ECC_PORT_CONFIGr(unit, local_port, rval)); 6004 } 6005 6006 BCM_IF_ERROR_RETURN(READ_E2ECC_MODEr(unit, &rval)); 6007 soc_reg_field_set(unit, E2ECC_MODEr, &rval, ENf, 6008 enable ? 1 : 0); 6009 BCM_IF_ERROR_RETURN(WRITE_E2ECC_MODEr(unit, rval)); 6010 6011 is_64q = 0; 6012 PBMP_E_ITER (unit, local_port) { 6013 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port, &is_64q)); 6014 if (is_64q) { 6015 /* E2ECC does not support 2-level scheduling mode */ 6016 /* Apply the register setting to the first 8 COSQ */ 6017 BCM_IF_ERROR_RETURN( 6018 READ_COLOR_DROP_EN_QLAYERr(unit, local_port, 0, &rval)); 6019 soc_reg_field_set(unit, COLOR_DROP_EN_QLAYERr, &rval, 6020 COLOR_DROP_ENf, enable ? 0x0 : 0xff); 6021 BCM_IF_ERROR_RETURN( 6022 WRITE_COLOR_DROP_EN_QLAYERr(unit, local_port, 0, rval)); 6023 } else { 6024 BCM_IF_ERROR_RETURN(READ_COLOR_DROP_ENr(unit, local_port, &rval)); 6025 soc_reg_field_set(unit, COLOR_DROP_ENr, &rval, 6026 COLOR_DROP_ENf, enable ? 0x0 : 0xff); 6027 BCM_IF_ERROR_RETURN(WRITE_COLOR_DROP_ENr(unit, local_port, rval)); 6028 } 6029 } 6030 6031 return BCM_E_NONE; 6032 } 6033 6034 /* 6035 * Function: 6036 * bcmi_gh2_cosq_pfc_class_resolve 6037 * Purpose: 6038 * Resolve the hw class index from bcmSwitchPFCClassNQueue types 6039 * Parameters: 6040 * sctype- (IN) bcmSwitchPFCClassNQueue type. 6041 * class - (OUT) hw class index. 6042 * Returns: 6043 * BCM_E_xxx 6044 * Notes: 6045 */ 6046 STATIC int 6047 bcmi_gh2_cosq_pfc_class_resolve(bcm_switch_control_t sctype, int *class) 6048 { 6049 if (class == NULL) { 6050 return BCM_E_PARAM; 6051 } 6052 6053 switch (sctype) { 6054 case bcmSwitchPFCClass7Queue: 6055 *class = 7; 6056 break; 6057 case bcmSwitchPFCClass6Queue: 6058 *class = 6; 6059 break; 6060 case bcmSwitchPFCClass5Queue: 6061 *class = 5; 6062 break; 6063 case bcmSwitchPFCClass4Queue: 6064 *class = 4; 6065 break; 6066 case bcmSwitchPFCClass3Queue: 6067 *class = 3; 6068 break; 6069 case bcmSwitchPFCClass2Queue: 6070 *class = 2; 6071 break; 6072 case bcmSwitchPFCClass1Queue: 6073 *class = 1; 6074 break; 6075 case bcmSwitchPFCClass0Queue: 6076 *class = 0; 6077 break; 6078 default: 6079 return BCM_E_UNAVAIL; 6080 } 6081 6082 return BCM_E_NONE; 6083 } 6084 6085 /* 6086 * Function: 6087 * bcmi_gh2_cosq_port_pfc_op 6088 * Purpose: 6089 * Set or clear the cosq id mapped to the bcmSwitchPFCClassNQueue type 6090 * Parameters: 6091 * unit - (IN) Unit number. 6092 * port - (IN) port ID 6093 * sctype- (IN) bcmSwitchPFCClassNQueue type. 6094 * op - (IN) opcode, add or clear 6095 * cosq - (IN) cosq id. 6096 * Returns: 6097 * BCM_E_xxx 6098 * Notes: 6099 */ 6100 int 6101 bcmi_gh2_cosq_port_pfc_op( 6102 int unit, 6103 bcm_port_t port, 6104 bcm_switch_control_t sctype, 6105 _bcm_cosq_op_t op, 6106 int cosq) 6107 { 6108 int class; 6109 uint32 class_bmp; 6110 int i; 6111 int is_64q_port = 0; 6112 gh2_cosq_node_t *node = NULL; 6113 int index; 6114 int local_port; 6115 int regidx_max = SOC_REG_NUMELS(unit, PRI2COS_PFCr); 6116 6117 BCM_IF_ERROR_RETURN(bcmi_gh2_cosq_pfc_class_resolve(sctype, &class)); 6118 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, port, &is_64q_port)); 6119 6120 if (is_64q_port) { 6121 if (BCM_GPORT_IS_SET(cosq)) { 6122 /* PFC class mapped to QG0~7(cosq is QLayer scheduler gport id) */ 6123 if (BCM_GPORT_IS_SCHEDULER(cosq)) { 6124 BCM_IF_ERROR_RETURN 6125 (bcmi_gh2_cosq_node_get(unit, cosq, 0, NULL, 6126 &local_port, NULL, &node)); 6127 if (local_port != port) { 6128 /* The scheduler is not belong to the port */ 6129 return BCM_E_PARAM; 6130 } 6131 if (node->node_level != GH2_COSQ_LEVEL_QLAYER) { 6132 /* Only available on QLayer scheduler */ 6133 return BCM_E_PARAM; 6134 } 6135 /* Get the QGx of the QLayer scheduler*/ 6136 index = node->child_idx; 6137 } else { 6138 /* Only available on QLayer scheduler */ 6139 return BCM_E_PARAM; 6140 } 6141 } else { 6142 index = cosq; 6143 } 6144 } else { 6145 index = cosq; 6146 } 6147 6148 if (op == _BCM_COSQ_OP_CLEAR) { 6149 for (i = 0; i < regidx_max; i++) { 6150 BCM_IF_ERROR_RETURN(READ_PRI2COS_PFCr(unit, port, 6151 i, &class_bmp)); 6152 class_bmp &= ~(1 << class); 6153 BCM_IF_ERROR_RETURN(WRITE_PRI2COS_PFCr(unit, port, 6154 i, class_bmp)); 6155 } 6156 } else if (op == _BCM_COSQ_OP_ADD) { 6157 if ((index < 0) || index > NUM_COS(unit)) { 6158 return BCM_E_PARAM; 6159 } 6160 6161 BCM_IF_ERROR_RETURN(READ_PRI2COS_PFCr(unit, port, index, &class_bmp)); 6162 class_bmp |= (1 << class); 6163 BCM_IF_ERROR_RETURN(WRITE_PRI2COS_PFCr(unit, port, index, class_bmp)); 6164 } else { 6165 return BCM_E_PARAM; 6166 } 6167 6168 return BCM_E_NONE; 6169 } 6170 6171 /* 6172 * Function: 6173 * bcmi_gh2_cosq_port_pfc_get 6174 * Purpose: 6175 * Get the cosq id mapped to the bcmSwitchPFCClassNQueue type 6176 * Parameters: 6177 * unit - (IN) Unit number. 6178 * port - (IN) port ID 6179 * sctype- (IN) bcmSwitchPFCClassNQueue type. 6180 * cosq - (OUT) cosq id mapped. 6181 * Returns: 6182 * BCM_E_xxx 6183 * Notes: 6184 */ 6185 int 6186 bcmi_gh2_cosq_port_pfc_get( 6187 int unit, 6188 bcm_port_t port, 6189 bcm_switch_control_t sctype, 6190 int *cosq) 6191 { 6192 int class; 6193 uint32 class_bmp; 6194 int i; 6195 int is_64q_port = 0; 6196 bcm_gport_t lvl0_node_gport = 0; 6197 bcm_gport_t lvl1_node_gport = 0; 6198 int regidx_max = SOC_REG_NUMELS(unit, PRI2COS_PFCr); 6199 int rv = BCM_E_NONE; 6200 6201 if (cosq == NULL) { 6202 return BCM_E_PARAM; 6203 } 6204 6205 BCM_IF_ERROR_RETURN(bcmi_gh2_cosq_pfc_class_resolve(sctype, &class)); 6206 6207 for (i = 0; i < regidx_max; i++) { 6208 BCM_IF_ERROR_RETURN(READ_PRI2COS_PFCr(unit, port, i, &class_bmp)); 6209 if (class_bmp & (1 << class)) { 6210 break; 6211 } 6212 } 6213 6214 if (i >= regidx_max) { 6215 return BCM_E_NOT_FOUND; 6216 } 6217 6218 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, port, &is_64q_port)); 6219 if (is_64q_port) { 6220 /* Get the lvl0 scheduler(QGroup scheduler) of the port */ 6221 rv = bcmi_gh2_cosq_gport_child_get(unit, port, 0, 6222 &lvl0_node_gport); 6223 if (SOC_SUCCESS(rv)) { 6224 /* 6225 * Get the i-th lvl1 scheduler(QLayer scheduler) of the 6226 * lvl0 scheduler 6227 */ 6228 BCM_IF_ERROR_RETURN( 6229 bcmi_gh2_cosq_gport_child_get(unit, lvl0_node_gport, i, 6230 &lvl1_node_gport)); 6231 *cosq = lvl1_node_gport; 6232 } else if (rv == BCM_E_NOT_FOUND) { 6233 /* cannot find child gport, it is legacy mode */ 6234 *cosq = i; 6235 } else { 6236 /* return for other errors */ 6237 return rv; 6238 } 6239 } else { 6240 *cosq = i; 6241 } 6242 6243 return BCM_E_NONE; 6244 } 6245 6246 #endif /* BCM_GREYHOUND2_SUPPORT */ 6247