cosq.c (388087B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * COS Queue Management 8 * Purpose: API to set different cosq, priorities, and scheduler registers. 9 */ 10 11 #include <shared/bsl.h> 12 13 #include <soc/defs.h> 14 #include <sal/core/libc.h> 15 16 #if defined(BCM_TOMAHAWK3_SUPPORT) 17 #include <soc/drv.h> 18 #include <soc/scache.h> 19 #include <soc/profile_mem.h> 20 #include <soc/debug.h> 21 #include <soc/tomahawk3.h> 22 #include <soc/dma.h> 23 #include <soc/mmu_config.h> 24 #include <soc/init/tomahawk3_idb_init.h> 25 #include <soc/pfc.h> 26 #include <soc/uc.h> 27 #include <soc/shared/qcm.h> 28 #include <soc/scache_dictionary.h> 29 30 #include <bcm/debug.h> 31 #include <bcm/error.h> 32 #include <bcm/cosq.h> 33 #include <bcm_int/esw/mbcm.h> 34 #include <bcm_int/esw/stack.h> 35 #include <bcm_int/esw/cosq.h> 36 #include <bcm_int/esw/virtual.h> 37 #include <bcm_int/esw/tomahawk3.h> 38 #include <bcm_int/esw/ecn.h> 39 #include <bcm_int/esw/oob.h> 40 #if defined(INCLUDE_PSTATS) 41 #include <bcm_int/esw/pstats.h> 42 #endif /* INCLUDE_PSTATS */ 43 #include <bcm_int/esw/pfc_deadlock.h> 44 #include <bcm_int/bst.h> 45 #include <bcm_int/esw_dispatch.h> 46 #include <bcm_int/bst.h> 47 #ifdef BCM_WARM_BOOT_SUPPORT 48 #include <bcm_int/esw/switch.h> 49 #endif /* BCM_WARM_BOOT_SUPPORT */ 50 #ifdef BCM_CMICM_SUPPORT 51 #include <soc/cmicm.h> 52 #endif /* BCM_CMICM_SUPPORT*/ 53 54 /*Local defines*/ 55 #define _BCM_TH3_NUM_QSCHED_PROFILES 8 56 #define _BCM_TH3_NUM_PG_PROP_PROFILES 8 57 #define _BCM_TH3_NUM_INTPRI_PG_MAP_PROFILES 8 58 #define _BCM_TH3_NUM_PFC_CLASS_PROFILES 8 59 #define _BCM_TH3_NUM_OOB_EGRQUEUE_MAP_PROFILES 4 60 #define _BCM_TH3_NUM_WRED_PROFILES 9 61 #define _BCM_TH3_QSCHED_MIN_WEIGHT 0 62 #define _BCM_TH3_QSCHED_MAX_WEIGHT 127 63 64 #define _TH3_ITMS_PER_DEV 2 65 #define _BCM_TH3_COS_DEFAULT 12 66 #define _BCM_TH3_COS_MAX 12 67 #define _BCM_TH3_MCQ_MODE_DEFAULT 2 68 #define _BCM_TH3_MMU_INFO(unit) _bcm_th3_mmu_info[(unit)] 69 #define _BCM_TH3_NUM_SCHEDULER_PER_PORT 12 70 #define _BCM_TH3_MAX_QUEUE_PER_PORT 12 71 #define _BCM_TH3_MAX_NUM_UCAST_QUEUE_PER_PORT 12 72 #define _BCM_TH3_MAX_NUM_MCAST_QUEUE_PER_PORT 6 73 #define _BCM_TH3_MAX_NUM_QUEUE_PER_PORT 12 74 #define _BCM_TH3_NUM_CPU_MCAST_QUEUE 48 75 76 /* Number of COSQs configured for this unit */ 77 #define _TH3_NUM_COS(unit) NUM_COS(unit) 78 79 #define _TH3_PORT_NUM_COS(unit, port) \ 80 ((IS_CPU_PORT(unit, port)) ? NUM_CPU_COSQ(unit) : \ 81 (IS_LB_PORT(unit, port)) ? 12 : _TH3_NUM_COS(unit)) 82 83 84 #define _BCM_TH3_NUM_TIME_DOMAIN 4 85 86 typedef struct _bcm_th3_cosq_time_info_s { 87 uint32 ref_count; 88 } _bcm_th3_cosq_time_info_t; 89 90 /* WRED can be enabled at per UC queue / port / service pool basis 91 MMU_WRED_AVG_QSIZE used entry: (20*12 + 20*4 + 4) = 324 92 */ 93 94 STATIC _bcm_th3_cosq_time_info_t th3_time_domain_info[BCM_MAX_NUM_UNITS][_BCM_TH3_NUM_TIME_DOMAIN] = { 95 { 96 {324}, /* Default all entries are pointing to TIME_0*/ 97 {0}, 98 {0}, 99 {0} 100 } 101 }; 102 103 #define TH3_WRED_CELL_FIELD_MAX 0x7ffff 104 #define TH3_WRED_PROFILE_INDEX_INVALID 0xffffffff 105 #define TH3_WRED_DROP_PROB_MAX_INDEX 14 106 107 /* 108 * index: degree, value: contangent(degree) * 100 109 * max value is 0x7ffff (19-bit) at 0 degree 110 */ 111 STATIC int 112 _bcm_th3_cotangent_lookup_table[] = 113 { 114 /* 0.. 5 */ 262143, 5728, 2863, 1908, 1430, 1143, 115 /* 6..11 */ 951, 814, 711, 631, 567, 514, 116 /* 12..17 */ 470, 433, 401, 373, 348, 327, 117 /* 18..23 */ 307, 290, 274, 260, 247, 235, 118 /* 24..29 */ 224, 214, 205, 196, 188, 180, 119 /* 30..35 */ 173, 166, 160, 153, 148, 142, 120 /* 36..41 */ 137, 132, 127, 123, 119, 115, 121 /* 42..47 */ 111, 107, 103, 100, 96, 93, 122 /* 48..53 */ 90, 86, 83, 80, 78, 75, 123 /* 54..59 */ 72, 70, 67, 64, 62, 60, 124 /* 60..65 */ 57, 55, 53, 50, 48, 46, 125 /* 66..71 */ 44, 42, 40, 38, 36, 34, 126 /* 72..77 */ 32, 30, 28, 26, 24, 23, 127 /* 78..83 */ 21, 19, 17, 15, 14, 12, 128 /* 84..89 */ 10, 8, 6, 5, 3, 1, 129 /* 90 */ 0 130 }; 131 132 /* 133 * Given a slope (angle in degrees) from 0 to 90, return the number of cells 134 * in the range from 0% drop probability to 100% drop probability. 135 * Same as TD2. 136 */ 137 STATIC int 138 _bcm_th3_angle_to_cells(int angle) 139 { 140 return (_bcm_th3_cotangent_lookup_table[angle]); 141 } 142 143 /* 144 * Given a number of packets in the range from 0% drop probability 145 * to 100% drop probability, return the slope (angle in degrees). 146 * Same as TD2. 147 */ 148 STATIC int 149 _bcm_th3_cells_to_angle(int packets) 150 { 151 int angle; 152 153 for (angle = 90; angle >= 0 ; angle--) { 154 if (packets <= _bcm_th3_cotangent_lookup_table[angle]) { 155 break; 156 } 157 } 158 return angle; 159 } 160 161 162 163 /* 164 * Convert HW drop probability to percent value 165 * Same as TH2. 166 */ 167 STATIC int 168 _bcm_th3_hw_drop_prob_to_percent[] = { 169 0, /* 0 */ 170 1, /* 1 */ 171 2, /* 2 */ 172 3, /* 3 */ 173 4, /* 4 */ 174 5, /* 5 */ 175 6, /* 6 */ 176 7, /* 7 */ 177 8, /* 8 */ 178 9, /* 9 */ 179 10, /* 10 */ 180 25, /* 11 */ 181 50, /* 12 */ 182 75, /* 13 */ 183 100, /* 14 */ 184 -1 /* 15 */ 185 }; 186 187 STATIC int 188 _bcm_th3_percent_to_drop_prob(int percent) 189 { 190 int i; 191 192 for (i = TH3_WRED_DROP_PROB_MAX_INDEX; i > 0 ; i--) { 193 if (percent >= _bcm_th3_hw_drop_prob_to_percent[i]) { 194 break; 195 } 196 } 197 return i; 198 } 199 200 STATIC int 201 _bcm_th3_drop_prob_to_percent(int drop_prob) { 202 return (_bcm_th3_hw_drop_prob_to_percent[drop_prob]); 203 } 204 205 /* WRED resolution table */ 206 #define _BCM_TH3_NUM_WRED_RESOLUTION_TABLE 4 207 STATIC uint32 _bcm_th3_wred_resolution_tbl[_BCM_TH3_NUM_WRED_RESOLUTION_TABLE] = { 208 1, 209 0, 210 0, 211 0, 212 }; 213 214 typedef struct _bcm_th3_cosq_node_s { 215 bcm_gport_t gport; 216 int numq; 217 int level; 218 int hw_index; 219 int in_use; 220 bcm_gport_t parent_gport; 221 int cos; 222 int strict_priority; /* port->L0 */ 223 /* int strict_priority_p;*/ /* L0->L1 */ 224 int fc_is_uc_only; 225 } _bcm_th3_cosq_node_t; 226 227 typedef struct _bcm_th3_cosq_cpu_cosq_config_s { 228 int q_min_limit; 229 int q_shared_limit; 230 uint8 q_limit_dynamic; 231 uint8 q_limit_enable; 232 uint8 q_color_limit_enable; 233 uint8 enable; 234 } _bcm_th3_cosq_cpu_cosq_config_t; 235 236 typedef struct _bcm_th3_cosq_port_info_s { 237 _bcm_th3_cosq_node_t ucast[_BCM_TH3_MAX_NUM_UCAST_QUEUE_PER_PORT]; 238 _bcm_th3_cosq_node_t mcast[_BCM_TH3_MAX_NUM_MCAST_QUEUE_PER_PORT]; 239 _bcm_th3_cosq_node_t sched[_BCM_TH3_NUM_SCHEDULER_PER_PORT]; 240 } _bcm_th3_cosq_port_info_t; 241 242 typedef struct _bcm_th3_cosq_cpu_port_info_s { 243 _bcm_th3_cosq_node_t sched[_BCM_TH3_NUM_SCHEDULER_PER_PORT]; 244 _bcm_th3_cosq_node_t mcast[_BCM_TH3_NUM_CPU_MCAST_QUEUE]; 245 } _bcm_th3_cosq_cpu_port_info_t; 246 247 typedef struct _bcm_th3_mmu_info_s { 248 int gport_tree_created; /* FALSE: No GPORT tree exists */ 249 _bcm_th3_cosq_port_info_t *_bcm_th3_port_info; 250 _bcm_th3_cosq_cpu_port_info_t *_bcm_th3_cpu_port_info; 251 int shared_limit[_TH3_ITMS_PER_DEV]; 252 } _bcm_th3_mmu_info_t; 253 254 255 STATIC _bcm_th3_mmu_info_t *_bcm_th3_mmu_info[BCM_MAX_NUM_UNITS]; /* MMU info */ 256 STATIC _bcm_th3_cosq_port_info_t *_bcm_th3_cosq_port_info[BCM_MAX_NUM_UNITS]; 257 STATIC _bcm_th3_cosq_cpu_port_info_t *_bcm_th3_cosq_cpu_port_info[BCM_MAX_NUM_UNITS]; 258 STATIC soc_profile_mem_t *_bcm_th3_cos_map_profile[BCM_MAX_NUM_UNITS]; 259 STATIC soc_profile_mem_t *_bcm_th3_wred_profile[BCM_MAX_NUM_UNITS]; 260 STATIC soc_profile_reg_t *_bcm_th3_prio2cos_profile[BCM_MAX_NUM_UNITS]; 261 STATIC soc_profile_mem_t *_bcm_th3_ifp_cos_map_profile[BCM_MAX_NUM_UNITS]; 262 STATIC _bcm_th3_cosq_cpu_cosq_config_t 263 *_bcm_th3_cosq_cpu_cosq_config[BCM_MAX_NUM_UNITS][SOC_TH3_NUM_CPU_QUEUES]; 264 265 /* Warmboot */ 266 #ifdef BCM_WARM_BOOT_SUPPORT 267 #define BCM_WB_VERSION_1_0 SOC_SCACHE_VERSION(1,0) 268 #define BCM_WB_VERSION_1_1 SOC_SCACHE_VERSION(1,1) 269 #define BCM_WB_VERSION_1_2 SOC_SCACHE_VERSION(1,2) 270 #define BCM_WB_VERSION_1_3 SOC_SCACHE_VERSION(1,3) 271 #define BCM_WB_VERSION_1_4 SOC_SCACHE_VERSION(1,4) 272 #define BCM_WB_VERSION_1_5 SOC_SCACHE_VERSION(1,5) 273 #define BCM_WB_VERSION_1_6 SOC_SCACHE_VERSION(1,6) 274 #define BCM_WB_VERSION_1_7 SOC_SCACHE_VERSION(1,7) 275 #define BCM_WB_VERSION_1_8 SOC_SCACHE_VERSION(1,8) 276 #define BCM_WB_DEFAULT_VERSION BCM_WB_VERSION_1_0 277 278 STATIC int 279 _bcm_th3_cosq_wb_alloc(int unit) 280 { 281 _bcm_th3_mmu_info_t *mmu_info = NULL; 282 soc_scache_handle_t scache_handle; 283 uint8 *scache_ptr = NULL; 284 int rv, alloc_size = 0, max_size = 4096 * 11; 285 _bcm_th3_cosq_cpu_port_info_t *cpu_port_info = NULL; 286 287 mmu_info = _bcm_th3_mmu_info[unit]; 288 if (mmu_info == NULL) { 289 return BCM_E_INIT; 290 } 291 292 cpu_port_info = _bcm_th3_cosq_cpu_port_info[unit]; 293 if (cpu_port_info == NULL) { 294 return BCM_E_INIT; 295 } 296 297 /* 298 * Sync _bcm_th3_mmu_info[unit]->shared_limit 299 */ 300 alloc_size += 1 * sizeof(int); 301 302 /* 303 * Sync _bcm_th3_cosq_cpu_port_info structure 304 */ 305 306 alloc_size += sizeof(_bcm_th3_cosq_cpu_port_info_t); 307 308 /* 309 * Sync the ref_count of IFP_COS_MAPm/COS_MAPm 310 */ 311 alloc_size += ((SOC_MEM_SIZE(unit, IFP_COS_MAPm) / _TH3_MMU_NUM_INT_PRI) - 1) * 312 sizeof(uint16); 313 314 /* 315 * Sync _bcm_th3_cosq_cpu_cosq_config_t structure for all CPU queues 316 */ 317 alloc_size += (SOC_TH3_NUM_CPU_QUEUES * 318 sizeof(_bcm_th3_cosq_cpu_cosq_config_t)); 319 /* 320 * Sync num_cos value 321 */ 322 alloc_size += sizeof(int); 323 324 /* 325 * Sync th3_sched_profile_info struture for all scheduler profiles 326 */ 327 alloc_size += (SOC_TH3_MAX_NUM_SCHED_PROFILE * 328 SOC_TH3_NUM_GP_QUEUES * 329 5 * sizeof(int)); 330 331 if (soc_feature(unit, soc_feature_pfc_deadlock)) { 332 alloc_size += (SOC_MAX_NUM_PORTS * 8 * sizeof(uint16)); 333 alloc_size += (SOC_MAX_NUM_PORTS * 8 * sizeof(uint32)); 334 } 335 336 /* 337 * Added TIME_DOMAIN ref count 338 */ 339 alloc_size += sizeof(_bcm_th3_cosq_time_info_t); 340 341 #ifdef BCM_TOMAHAWK3_SUPPORT 342 if (soc_feature(unit, soc_feature_ecn_wred)) { 343 uint32 scache_size = 0; 344 BCM_IF_ERROR_RETURN( 345 bcmi_xgs5_ecn_scache_size_get(unit, &scache_size)); 346 alloc_size += scache_size; 347 } 348 #endif 349 350 351 352 /* 353 * Sync _bcm_th3_cosq_cpu_cosq_config_t structure for all CPU queues 354 */ 355 alloc_size += (_BCM_TH3_NUM_WRED_RESOLUTION_TABLE * 356 sizeof(uint32)); 357 358 /* Reserving some space scache for future usecase (max_size) */ 359 if (alloc_size < max_size) { 360 alloc_size = max_size; 361 } else { 362 /* Required size more than max size allocated for Cosq */ 363 return BCM_E_INIT; 364 } 365 366 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 0); 367 368 rv = _bcm_esw_scache_ptr_get(unit, scache_handle, TRUE, alloc_size, 369 &scache_ptr, BCM_WB_DEFAULT_VERSION, NULL); 370 371 if (rv == BCM_E_NOT_FOUND) { 372 rv = BCM_E_NONE; 373 } 374 375 return rv; 376 } 377 #endif /* BCM_WARM_BOOT_SUPPORT */ 378 379 380 /* Function to Set Default Scheduler Configuration for all the ports */ 381 STATIC int 382 _bcm_th3_cosq_sched_default_config(int unit) 383 { 384 _bcm_th3_cosq_port_info_t *port_info = NULL; 385 _bcm_th3_cosq_cpu_port_info_t *cpu_port_info = NULL; 386 bcm_port_t port; 387 int default_mode = BCM_COSQ_WEIGHTED_ROUND_ROBIN, default_weight = 1; 388 int i; 389 390 port = 0; 391 cpu_port_info = &_bcm_th3_cosq_cpu_port_info[unit][port]; 392 for (i = 0; i < _BCM_TH3_NUM_SCHEDULER_PER_PORT; i++) { 393 BCM_IF_ERROR_RETURN 394 (bcm_th3_cosq_gport_sched_set(unit, cpu_port_info->sched[i].gport, 395 -1, default_mode, default_weight)); 396 } 397 for (i = 0; i < _BCM_TH3_NUM_CPU_MCAST_QUEUE; i++) { 398 BCM_IF_ERROR_RETURN 399 (bcm_th3_cosq_gport_sched_set(unit, cpu_port_info->mcast[i].gport, 400 -1, default_mode, default_weight)); 401 } 402 403 PBMP_ALL_ITER(unit, port) { 404 if (IS_CPU_PORT(unit, port) || IS_LB_PORT(unit, port)) { 405 continue; 406 } else { 407 port_info = &_bcm_th3_cosq_port_info[unit][port]; 408 } 409 for (i = 0; i < _BCM_TH3_NUM_SCHEDULER_PER_PORT; i++) { 410 if (!port_info->sched[i].in_use || (port_info->sched[i].numq == 0)) { 411 continue; 412 } 413 BCM_IF_ERROR_RETURN 414 (bcm_th3_cosq_gport_sched_set(unit, port_info->sched[i].gport, 415 -1, default_mode, default_weight)); 416 } 417 for (i = 0; i < _bcm_th3_get_num_ucq(unit); i++) { 418 if (!port_info->ucast[i].in_use) 419 continue; 420 BCM_IF_ERROR_RETURN 421 (bcm_th3_cosq_gport_sched_set(unit, port_info->ucast[i].gport, 422 -1, default_mode, default_weight)); 423 } 424 for (i = 0; i < _bcm_th3_get_num_mcq(unit); i++) { 425 if (!port_info->mcast[i].in_use) 426 continue; 427 BCM_IF_ERROR_RETURN 428 (bcm_th3_cosq_gport_sched_set(unit, port_info->mcast[i].gport, 429 -1, default_mode, default_weight)); 430 } 431 } 432 return BCM_E_NONE; 433 } 434 435 STATIC int 436 _bcm_th3_cosq_gport_default_config(int unit) 437 { 438 BCM_IF_ERROR_RETURN 439 (_bcm_th3_cosq_sched_default_config(unit)); 440 441 return BCM_E_NONE; 442 } 443 444 /* 445 * Function: 446 * _bcm_th3_cosq_node_get 447 * Purpose: 448 * Get internal information of queue group or scheduler type GPORT 449 * Parameters: 450 * unit - (IN) unit number 451 * gport - (IN) queue group/scheduler GPORT identifier 452 * modid - (OUT) module identifier 453 * port - (OUT) port number 454 * id - (OUT) queue group or scheduler identifier 455 * node - (OUT) node structure for the specified GPORT 456 * Returns: 457 * BCM_E_XXX 458 */ 459 STATIC int 460 _bcm_th3_cosq_node_get(int unit, bcm_gport_t gport, bcm_module_t *modid, 461 bcm_port_t *port, int *id, _bcm_th3_cosq_node_t **node) 462 { 463 _bcm_th3_cosq_port_info_t *port_info = NULL; 464 _bcm_th3_cosq_cpu_port_info_t *cpu_port_info = NULL; 465 _bcm_th3_cosq_node_t *node_base = NULL; 466 bcm_module_t modid_out; 467 bcm_port_t port_out; 468 uint32 encap_id; 469 int index; 470 471 if (_bcm_th3_cosq_port_info[unit] == NULL) { 472 return BCM_E_INIT; 473 } 474 if (_bcm_th3_cosq_cpu_port_info[unit] == NULL) { 475 return BCM_E_INIT; 476 } 477 478 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 479 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &modid_out)); 480 port_out = BCM_GPORT_UCAST_QUEUE_GROUP_SYSPORTID_GET(gport); 481 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 482 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &modid_out)); 483 port_out = BCM_GPORT_MCAST_QUEUE_GROUP_SYSPORTID_GET(gport); 484 } else if (BCM_GPORT_IS_SCHEDULER(gport)) { 485 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &modid_out)); 486 port_out = BCM_GPORT_SCHEDULER_GET(gport) & 0xff; 487 } else { 488 return BCM_E_PORT; 489 } 490 491 if (!SOC_PORT_VALID(unit, port_out)) { 492 return BCM_E_PORT; 493 } 494 if (IS_CPU_PORT(unit, port_out)) { 495 cpu_port_info = &_bcm_th3_cosq_cpu_port_info[unit][port_out]; 496 } else { 497 port_info = &_bcm_th3_cosq_port_info[unit][port_out]; 498 } 499 500 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 501 encap_id = BCM_GPORT_UCAST_QUEUE_GROUP_QID_GET(gport); 502 index = encap_id; 503 if (index >= _bcm_th3_get_num_ucq(unit)) { 504 return BCM_E_PORT; 505 } 506 node_base = port_info->ucast; 507 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 508 encap_id = BCM_GPORT_MCAST_QUEUE_GROUP_QID_GET(gport); 509 index = encap_id; 510 if (!IS_CPU_PORT(unit, port_out) && 511 (index >= _bcm_th3_get_num_mcq(unit))) { 512 return BCM_E_PORT; 513 } 514 if (IS_CPU_PORT(unit, port_out) && (index >= _BCM_TH3_NUM_CPU_MCAST_QUEUE)) { 515 return BCM_E_PORT; 516 } 517 if (IS_CPU_PORT(unit, port_out)) { 518 node_base = cpu_port_info->mcast; 519 } else { 520 node_base = port_info->mcast; 521 } 522 } else { /* scheduler */ 523 encap_id = (BCM_GPORT_SCHEDULER_GET(gport) >> 16) & 0x3ff; 524 index = encap_id; 525 if (index >= _BCM_TH3_NUM_SCHEDULER_PER_PORT) { 526 return BCM_E_PORT; 527 } 528 if (IS_CPU_PORT(unit, port_out)) { 529 node_base = cpu_port_info->sched; 530 } else { 531 node_base = port_info->sched; 532 } 533 } 534 535 if ((node_base == NULL) || 536 (node_base[index].numq == 0) || 537 (node_base[index].in_use == 0)) { 538 return BCM_E_NOT_FOUND; 539 } 540 541 if (modid != NULL) { 542 *modid = modid_out; 543 } 544 if (port != NULL) { 545 *port = port_out; 546 } 547 if (id != NULL) { 548 *id = encap_id; 549 } 550 if (node != NULL) { 551 *node = &node_base[index]; 552 } 553 554 return BCM_E_NONE; 555 } 556 557 /* 558 * Function: 559 * _bcm_th3_rqe_q_init 560 * Purpose: 561 * Initialize RQE registers 562 * Parameters: 563 * unit - unit number 564 * Returns: 565 * BCM_E_XXX 566 */ 567 STATIC int 568 _bcm_th3_rqe_q_init(int unit) 569 { 570 uint32 rval; 571 uint16 dev_id; 572 uint8 rev_id; 573 574 soc_cm_get_id(unit, &dev_id, &rev_id); 575 576 rval = 0; 577 SOC_IF_ERROR_RETURN(READ_CPU_LO_RQE_Q_NUMr(unit, &rval)); 578 if (rev_id == BCM56980_A0_REV_ID) { 579 soc_reg_field_set(unit, CPU_LO_RQE_Q_NUMr, &rval, RQE_Q_NUMf, _TH3_A0_CPU_LO_RQE_Q_NUM); 580 } else { 581 soc_reg_field_set(unit, CPU_LO_RQE_Q_NUMr, &rval, RQE_Q_NUMf, _TH3_CPU_LO_RQE_Q_NUM); 582 } 583 SOC_IF_ERROR_RETURN(WRITE_CPU_LO_RQE_Q_NUMr(unit, rval)); 584 585 rval = 0; 586 SOC_IF_ERROR_RETURN(READ_CPU_HI_RQE_Q_NUMr(unit, &rval)); 587 if (rev_id == BCM56980_A0_REV_ID) { 588 soc_reg_field_set(unit, CPU_HI_RQE_Q_NUMr, &rval, RQE_Q_NUMf, _TH3_A0_CPU_HI_RQE_Q_NUM); 589 } else { 590 soc_reg_field_set(unit, CPU_HI_RQE_Q_NUMr, &rval, RQE_Q_NUMf, _TH3_CPU_HI_RQE_Q_NUM); 591 } 592 SOC_IF_ERROR_RETURN(WRITE_CPU_HI_RQE_Q_NUMr(unit, rval)); 593 594 return BCM_E_NONE; 595 } 596 597 /* 598 * Function: 599 * _bcm_th3_ecn_init 600 * Purpose: 601 * Initialize (clear) all ECN memories/registers 602 * Parameters: 603 * unit - unit number 604 * Returns: 605 * BCM_E_XXX 606 */ 607 STATIC int 608 _bcm_th3_ecn_init(int unit) 609 { 610 egr_ip_to_int_cn_mapping_entry_t entry_egr_ip_int_cn; 611 int count, i; 612 uint32 fld_val; 613 614 BCM_IF_ERROR_RETURN(_bcm_esw_ecn_init(unit)); 615 616 /* Perform additional Tomahawk3 specific ECN initialization */ 617 /* EGR_IP_TO_INT_CN_MAPPING is identical to IP_TO_INT_CN_MAPPING table 618 */ 619 if (!SOC_WARM_BOOT(unit)) { 620 count = soc_mem_index_count(unit, EGR_IP_TO_INT_CN_MAPPINGm); 621 for (i = 0; i < count; i++) { 622 sal_memset(&entry_egr_ip_int_cn, 0, sizeof(entry_egr_ip_int_cn)); 623 switch (i) { 624 case 0: 625 fld_val = _BCM_ECN_INT_CN_NON_RESPONSIVE_DROP; 626 break; 627 case 1: 628 fld_val = _BCM_ECN_INT_CN_RESPONSIVE_DROP; 629 break; 630 case 6: 631 case 7: 632 fld_val = _BCM_ECN_INT_CN_CONGESTION_MARK_ECN; 633 break; 634 default: 635 fld_val = _BCM_ECN_INT_CN_NON_CONGESTION_MARK_ECN; 636 break; 637 } 638 soc_mem_field32_set(unit, EGR_IP_TO_INT_CN_MAPPINGm, 639 &entry_egr_ip_int_cn, INT_CNf, fld_val); 640 SOC_IF_ERROR_RETURN 641 (soc_mem_write(unit, EGR_IP_TO_INT_CN_MAPPINGm, MEM_BLOCK_ALL, 642 i, (void *)&entry_egr_ip_int_cn)); 643 } 644 } 645 return BCM_E_NONE; 646 } 647 648 /* 649 * Function: 650 * _bcm_th3_cosq_cleanup 651 * Purpose: 652 * Clean resource in case of error during Cosq Init 653 * Parameters: 654 * unit - unit number 655 * Returns: 656 * No return value 657 */ 658 STATIC void 659 _bcm_th3_cosq_cleanup(int unit) 660 { 661 if (_bcm_th3_cosq_port_info[unit] != NULL) { 662 sal_free(_bcm_th3_cosq_port_info[unit]); 663 _bcm_th3_cosq_port_info[unit] = NULL; 664 } 665 666 if (_bcm_th3_cosq_cpu_port_info[unit] != NULL) { 667 sal_free(_bcm_th3_cosq_cpu_port_info[unit]); 668 _bcm_th3_cosq_cpu_port_info[unit] = NULL; 669 } 670 671 if (_bcm_th3_mmu_info[unit] != NULL) { 672 sal_free(_bcm_th3_mmu_info[unit]); 673 _bcm_th3_mmu_info[unit] = NULL; 674 } 675 676 if (_bcm_th3_cos_map_profile[unit] != NULL) { 677 soc_profile_mem_destroy(unit, _bcm_th3_cos_map_profile[unit]); 678 sal_free(_bcm_th3_cos_map_profile[unit]); 679 _bcm_th3_cos_map_profile[unit] = NULL; 680 } 681 682 if (_bcm_th3_ifp_cos_map_profile[unit] != NULL) { 683 soc_profile_mem_destroy(unit, _bcm_th3_ifp_cos_map_profile[unit]); 684 sal_free(_bcm_th3_ifp_cos_map_profile[unit]); 685 _bcm_th3_ifp_cos_map_profile[unit] = NULL; 686 } 687 688 if (_bcm_th3_wred_profile[unit] != NULL) { 689 soc_profile_mem_destroy(unit, _bcm_th3_wred_profile[unit]); 690 sal_free(_bcm_th3_wred_profile[unit]); 691 _bcm_th3_wred_profile[unit] = NULL; 692 } 693 694 if (_bcm_th3_prio2cos_profile[unit] != NULL) { 695 soc_profile_reg_destroy(unit, _bcm_th3_prio2cos_profile[unit]); 696 sal_free(_bcm_th3_prio2cos_profile[unit]); 697 _bcm_th3_prio2cos_profile[unit] = NULL; 698 } 699 700 #if defined(INCLUDE_PSTATS) 701 if (_BCM_PSTATS_UNIT_DRIVER(unit) != NULL) { 702 _bcm_pstats_deinit(unit); 703 } 704 #endif /* INCLUDE_PSTATS */ 705 706 (void)_bcm_bst_detach(unit); 707 708 #if defined(BCM_TOMAHAWK3_SUPPORT) && defined(INCLUDE_L3) 709 bcmi_ecn_map_clean_up(unit); 710 #endif 711 (void)_bcm_th3_pfc_deadlock_deinit(unit); 712 713 return; 714 } 715 716 /* 717 * Function: 718 * bcm_th3_cosq_detach 719 * Purpose: 720 * Discard all COS schedule/mapping state. 721 * Parameters: 722 * unit - unit number 723 * Returns: 724 * BCM_E_XXX 725 */ 726 int 727 bcm_th3_cosq_detach(int unit, int software_state_only) 728 { 729 _bcm_th3_cosq_cleanup(unit); 730 731 return BCM_E_NONE; 732 } 733 734 /* 735 * Function: 736 * _bcm_th3_cosq_sched_get 737 * Purpose: 738 * Get scheduling mode setting 739 * Parameters: 740 * unit - (IN) unit number 741 * port - (IN) port number or GPORT identifier 742 * cosq - (IN) COS queue number 743 * mode - (OUT) scheduling mode (BCM_COSQ_XXX) 744 * weight - (OUT) weight 745 * Returns: 746 * BCM_E_XXX 747 */ 748 STATIC int 749 _bcm_th3_cosq_sched_get(int unit, bcm_port_t gport, bcm_cos_queue_t cosq, 750 int *mode, int *weight) 751 { 752 soc_th3_sched_mode_e sched_mode; 753 bcm_port_t local_port; 754 int lvl = SOC_TH3_NODE_LVL_L0, mc = 0; 755 756 if (cosq < 0) { 757 if (cosq == -1) { 758 /* caller needs to resolve the wild card value (-1) */ 759 return BCM_E_INTERNAL; 760 } else { /* reject all other negative value */ 761 return BCM_E_PARAM; 762 } 763 } 764 765 766 BCM_IF_ERROR_RETURN 767 (_bcm_th3_cosq_localport_resolve(unit, gport, &local_port)); 768 if (BCM_GPORT_IS_SCHEDULER(gport)) { 769 lvl = SOC_TH3_NODE_LVL_L0; 770 } else if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport) || 771 BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 772 lvl = SOC_TH3_NODE_LVL_L1; 773 mc = BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport) ? 1 : 0; 774 } else if (IS_CPU_PORT(unit, local_port)) { 775 lvl = SOC_TH3_NODE_LVL_L1; 776 mc = 1; 777 } 778 BCM_IF_ERROR_RETURN( 779 soc_th3_cosq_sched_mode_get(unit, local_port, lvl, cosq, 780 &sched_mode, weight, mc)); 781 switch(sched_mode) { 782 case SOC_TH3_SCHED_MODE_STRICT: 783 *mode = BCM_COSQ_STRICT; 784 break; 785 case SOC_TH3_SCHED_MODE_WRR: 786 *mode = BCM_COSQ_WEIGHTED_ROUND_ROBIN; 787 break; 788 case SOC_TH3_SCHED_MODE_WERR: 789 *mode = BCM_COSQ_DEFICIT_ROUND_ROBIN; 790 break; 791 default: 792 return BCM_E_INTERNAL; 793 break; 794 } 795 return BCM_E_NONE; 796 } 797 798 /* 799 * Function: 800 * _bcm_th3_cosq_sched_set 801 * Purpose: 802 * Set scheduling mode 803 * Parameters: 804 * unit - (IN) unit number 805 * port - (IN) port number or GPORT identifier 806 * cosq - (IN) COS queue number 807 * mode - (IN) scheduling mode (BCM_COSQ_XXX) 808 * weight - (IN) weight 809 * Returns: 810 * BCM_E_XXX 811 */ 812 STATIC int 813 _bcm_th3_cosq_sched_set(int unit, bcm_port_t gport, bcm_cos_queue_t cosq, 814 int mode, int weight) 815 { 816 soc_th3_sched_mode_e sched_mode; 817 bcm_port_t local_port; 818 int lwts = 1, child_index=0, lvl = SOC_TH3_NODE_LVL_L0, mc = 0; 819 820 if (cosq < 0) { 821 if (cosq == -1) { 822 /* caller needs to resolve the wild card value (-1) */ 823 return BCM_E_INTERNAL; 824 } else { /* reject all other negative value */ 825 return BCM_E_PARAM; 826 } 827 } 828 if ((weight < _BCM_TH3_QSCHED_MIN_WEIGHT) || (weight > _BCM_TH3_QSCHED_MAX_WEIGHT)) { 829 return BCM_E_PARAM; 830 } 831 832 switch(mode) { 833 case BCM_COSQ_STRICT: 834 sched_mode = SOC_TH3_SCHED_MODE_STRICT; 835 lwts = 0; 836 break; 837 case BCM_COSQ_ROUND_ROBIN: 838 sched_mode = SOC_TH3_SCHED_MODE_WRR; 839 lwts = 1; 840 break; 841 case BCM_COSQ_WEIGHTED_ROUND_ROBIN: 842 sched_mode = SOC_TH3_SCHED_MODE_WRR; 843 lwts = weight; 844 break; 845 case BCM_COSQ_DEFICIT_ROUND_ROBIN: 846 sched_mode = SOC_TH3_SCHED_MODE_WERR; 847 lwts = weight; 848 break; 849 default: 850 return BCM_E_PARAM; 851 } 852 853 /* Weight = 0 corresponds to Strict Mode */ 854 if (lwts == 0) { 855 sched_mode = SOC_TH3_SCHED_MODE_STRICT; 856 } 857 858 child_index = cosq; 859 BCM_IF_ERROR_RETURN 860 (_bcm_th3_cosq_localport_resolve(unit, gport, &local_port)); 861 862 if (BCM_GPORT_IS_SCHEDULER(gport)) { 863 /* We need to set lvl = L0(schedular node) so that sched mode is set at it's parent */ 864 lvl = SOC_TH3_NODE_LVL_L0; 865 } else if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport) || 866 BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 867 /* We need to set lvl = L1(UC/MC nodes) so that sched mode is set at it's parent */ 868 lvl = SOC_TH3_NODE_LVL_L1; 869 mc = BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport) ? 1 : 0; 870 } else if (IS_CPU_PORT(unit, local_port)) { 871 lvl = SOC_TH3_NODE_LVL_L1; 872 mc = 1; 873 } 874 BCM_IF_ERROR_RETURN(soc_th3_cosq_sched_mode_set(unit, local_port, 875 lvl, 876 child_index, 877 sched_mode, lwts, mc)); 878 879 return BCM_E_NONE; 880 } 881 882 /* 883 * Function: 884 * bcm_tomahaw3_cosq_port_sched_config_get 885 * Purpose: 886 * Retrieve class-of-service policy and corresponding weights and mode 887 * Parameters: 888 * unit - (IN) unit number 889 * pbm - (IN) port bitmap 890 * weight_arr_size - (IN) Size of weights array 891 * mode - (OUT) Scheduling mode (BCM_COSQ_XXX) 892 * weights - (OUT) Weights for each COS queue 893 * weight_arr_count - (OUT) Actual size of weights array 894 * Returns: 895 * BCM_E_XXX 896 */ 897 int 898 bcm_tomahawk3_cosq_port_sched_config_get(int unit, bcm_pbmp_t pbm, int weight_arr_size, 899 int *weights, int *weight_arr_count, int *mode) 900 { 901 bcm_port_t port; 902 int i, num_weights; 903 904 BCM_PBMP_ITER(pbm, port) { 905 if (IS_CPU_PORT(unit, port) && SOC_PBMP_NEQ(pbm, PBMP_CMIC(unit))) { 906 continue; 907 } 908 if (weights == NULL) { 909 return BCM_E_PARAM; 910 } 911 if (weight_arr_count == NULL) { 912 return BCM_E_PARAM; 913 } 914 if (weight_arr_size > _TH3_NUM_COS(unit)) { 915 num_weights = _TH3_NUM_COS(unit); 916 } else { 917 num_weights = weight_arr_size; 918 } 919 *weight_arr_count = num_weights; 920 921 for (i = 0; i < num_weights; i++) { 922 BCM_IF_ERROR_RETURN( 923 _bcm_th3_cosq_sched_get(unit, port, i, mode, &weights[i])); 924 } 925 } 926 927 return BCM_E_NONE; 928 } 929 930 /* 931 * Function: 932 * bcm_tomahawk3_cosq_port_sched_config_set 933 * Purpose: 934 * Set up class-of-service policy and corresponding weights and mode 935 * Parameters: 936 * unit - (IN) unit number 937 * pbm - (IN) port bitmap 938 * mode - (IN) Scheduling mode (BCM_COSQ_xxx) 939 * weight_arr_size - (IN) Size of the weights array 940 * weights - (IN) Weights for each COS queue 941 * Returns: 942 * BCM_E_XXX 943 */ 944 int 945 bcm_tomahawk3_cosq_port_sched_config_set(int unit, bcm_pbmp_t pbm, 946 int mode, int weight_arr_size, int *weights) 947 { 948 bcm_port_t port; 949 int num_weights, i; 950 951 BCM_PBMP_ITER(pbm, port) { 952 if (weight_arr_size > _TH3_NUM_COS(unit)) { 953 return BCM_E_PARAM; 954 } else { 955 num_weights = weight_arr_size; 956 } 957 958 if (weights == NULL) { 959 return BCM_E_PARAM; 960 } 961 for (i = 0; i < num_weights; i++) { 962 BCM_IF_ERROR_RETURN 963 (_bcm_th3_cosq_sched_set(unit, port, i, mode, weights[i])); 964 } 965 } 966 967 return BCM_E_NONE; 968 } 969 970 /* 971 * Function: 972 * bcm_tomahawk3_cosq_sched_config_set 973 * Purpose: 974 * Set up class-of-service policy and corresponding weights and mode 975 * Parameters: 976 * unit - StrataSwitch unit number. 977 * mode - Scheduling mode, one of BCM_COSQ_xxx 978 * weight_arr_size - Size of the weights array 979 * weights - Weights for each COS queue 980 * Unused if mode is BCM_COSQ_STRICT. 981 * Indicates number of packets sent before going on to 982 * the next COS queue. 983 * Returns: 984 * BCM_E_XXX 985 */ 986 987 int 988 bcm_tomahawk3_cosq_sched_config_set(int unit, int mode, int weight_arr_size, int *weights) 989 { 990 bcm_pbmp_t pbmp; 991 992 if (soc_feature(unit, soc_feature_ets)) { 993 BCM_PBMP_ASSIGN(pbmp, PBMP_CMIC(unit)); 994 } else { 995 BCM_PBMP_ASSIGN(pbmp, PBMP_ALL(unit)); 996 } 997 998 return (bcm_tomahawk3_cosq_port_sched_config_set(unit, pbmp, mode, weight_arr_size, 999 weights)); 1000 } 1001 1002 /* 1003 * Function: 1004 * bcm_tomahawk3_cosq_sched_config_get 1005 * Purpose: 1006 * Retrieve class-of-service policy and corresponding weights and mode 1007 * Parameters: 1008 * unit - StrataSwitch unit number. 1009 * mode_ptr - (output) Scheduling mode, one of BCM_COSQ_xxx 1010 * weights - (output) Weights for each COS queue 1011 * Unused if mode is BCM_COSQ_STRICT. 1012 * Returns: 1013 * BCM_E_XXX 1014 */ 1015 1016 int 1017 bcm_tomahawk3_cosq_sched_config_get(int unit, int weight_arr_size, 1018 int *weights, int *weight_arr_count, 1019 int *mode) 1020 { 1021 bcm_pbmp_t pbmp; 1022 1023 if (soc_feature(unit, soc_feature_ets)) { 1024 BCM_PBMP_ASSIGN(pbmp, PBMP_CMIC(unit)); 1025 } else { 1026 BCM_PBMP_ASSIGN(pbmp, PBMP_ALL(unit)); 1027 } 1028 1029 return (bcm_tomahawk3_cosq_port_sched_config_get(unit, pbmp, weight_arr_size, 1030 weights, weight_arr_count, mode)); 1031 } 1032 1033 1034 /* 1035 * Function: 1036 * bcm_th3_cosq_port_sched_get 1037 * Purpose: 1038 * Retrieve class-of-service policy and corresponding weights and delay 1039 * Parameters: 1040 * unit - (IN) unit number 1041 * pbm - (IN) port bitmap 1042 * mode - (OUT) Scheduling mode (BCM_COSQ_XXX) 1043 * weights - (OUT) Weights for each COS queue 1044 * delay - This parameter is not used 1045 * Returns: 1046 * BCM_E_XXX 1047 */ 1048 int 1049 bcm_th3_cosq_port_sched_get(int unit, bcm_pbmp_t pbm, 1050 int *mode, int *weights, int *delay) 1051 { 1052 return BCM_E_UNAVAIL; 1053 } 1054 1055 /* 1056 * Function: 1057 * bcm_th3_cosq_port_sched_set 1058 * Purpose: 1059 * Set up class-of-service policy and corresponding weights and delay 1060 * Parameters: 1061 * unit - (IN) unit number 1062 * pbm - (IN) port bitmap 1063 * mode - (IN) Scheduling mode (BCM_COSQ_xxx) 1064 * weights - (IN) Weights for each COS queue 1065 * delay - This parameter is not used 1066 * Returns: 1067 * BCM_E_XXX 1068 */ 1069 int 1070 bcm_th3_cosq_port_sched_set(int unit, bcm_pbmp_t pbm, 1071 int mode, const int *weights, int delay) 1072 { 1073 return BCM_E_UNAVAIL; 1074 } 1075 1076 1077 1078 int 1079 _bcm_th3_cosq_rx_queue_channel_set(int unit, 1080 bcm_cos_queue_t parent_cos, 1081 bcm_cos_queue_t queue_id, 1082 int enable) 1083 { 1084 #if defined(BCM_CMICX_SUPPORT) 1085 1086 if(soc_feature(unit, soc_feature_cmicx)) { 1087 int pci_cmc = SOC_PCI_CMC(unit); 1088 int chan_id = -1; 1089 int start_chan_id = 0; 1090 uint32 chan_off; 1091 uint32 reg_addr, reg_val; 1092 uint32 ix; 1093 uint32 max_rx_channels; 1094 1095 if ((parent_cos >= 0) && (parent_cos <= 6)) { 1096 chan_id = parent_cos + 1; 1097 } else { 1098 return BCM_E_PARAM; 1099 } 1100 1101 if (!SHR_BITGET(CPU_ARM_QUEUE_BITMAP(unit, pci_cmc), queue_id)) { 1102 return BCM_E_PARAM; 1103 } 1104 1105 soc_dma_max_rx_channels_get(unit, &max_rx_channels); 1106 1107 for (ix = start_chan_id; ix < (start_chan_id + max_rx_channels); ix++) { 1108 chan_off = ix % max_rx_channels; 1109 soc_dma_cos_ctrl_reg_addr_get(unit, pci_cmc, chan_off, 1110 queue_id, ®_addr); 1111 reg_val = soc_pci_read(unit, reg_addr); 1112 1113 if (enable == 1) { 1114 if (ix == (uint32)chan_id) { 1115 reg_val |= ((1U) << (queue_id % 32)); 1116 } else { 1117 /* Clear all other channels */ 1118 reg_val &= ~((1U) << (queue_id % 32)); 1119 } 1120 } else { 1121 if (ix == (uint32)chan_id) { 1122 reg_val &= ~((1U) << (queue_id % 32)); 1123 } 1124 } 1125 /* Incoporate the reserved queues (if any on this device) 1126 * into the CMIC programming, */ 1127 reg_val |= 1128 CPU_ARM_RSVD_QUEUE_BITMAP(unit, pci_cmc)[queue_id / 32]; 1129 soc_pci_write(unit, reg_addr, reg_val); 1130 } 1131 } 1132 #endif 1133 return BCM_E_NONE; 1134 } 1135 1136 /* Function to attach any of the 48 L1 MC Queue to one of the 10 L0 nodes 1137 */ 1138 STATIC int 1139 bcm_th3_cosq_cpu_gport_attach(int unit, bcm_gport_t input_gport, 1140 bcm_gport_t parent_gport, bcm_cos_queue_t cosq) 1141 { 1142 bcm_port_t parent_port, input_port; 1143 _bcm_th3_cosq_node_t *input_node = NULL, *parent_node = NULL; 1144 int phy_port, mmu_port; 1145 int input_cos = 0, parent_cos = 0; 1146 int cpu_sched_base = 0, cpu_mc_base = 0; 1147 soc_info_t *si = &SOC_INFO(unit); 1148 1149 /* Post Default tree created, expected Input Gport is of MC Gport 1150 * and expected Parent Gport is new L0 Parent 1151 */ 1152 if (_BCM_TH3_MMU_INFO(unit)->gport_tree_created == FALSE) { 1153 if (((BCM_GPORT_IS_MCAST_QUEUE_GROUP(input_gport)) && 1154 (!BCM_GPORT_IS_SCHEDULER(parent_gport))) || 1155 (!(BCM_GPORT_IS_MCAST_QUEUE_GROUP(input_gport)) && 1156 (!BCM_GPORT_IS_SCHEDULER(input_gport)))) { 1157 return BCM_E_PARAM; 1158 } 1159 } else if ((!BCM_GPORT_IS_SCHEDULER(parent_gport)) || 1160 (!BCM_GPORT_IS_MCAST_QUEUE_GROUP(input_gport))) { 1161 return BCM_E_PARAM; 1162 } 1163 BCM_IF_ERROR_RETURN 1164 (_bcm_th3_cosq_node_get(unit, input_gport, NULL, &input_port, NULL, 1165 &input_node)); 1166 if (BCM_GPORT_IS_SCHEDULER(parent_gport)) { 1167 BCM_IF_ERROR_RETURN 1168 (_bcm_th3_cosq_node_get(unit, parent_gport, NULL, &parent_port, NULL, 1169 &parent_node)); 1170 } else { 1171 BCM_IF_ERROR_RETURN 1172 (_bcm_th3_cosq_localport_resolve(unit, parent_gport, &parent_port)); 1173 parent_node = NULL; 1174 } 1175 1176 if (!IS_CPU_PORT(unit, parent_port)) { 1177 return BCM_E_PARAM; 1178 } 1179 1180 /* Return BCM_E_EXISTS when queue to be attached is 1181 already attached to the given gport */ 1182 if ((_BCM_TH3_MMU_INFO(unit)->gport_tree_created == TRUE) && 1183 (input_node->parent_gport == parent_gport)) { 1184 return BCM_E_EXISTS; 1185 } 1186 1187 phy_port = si->port_l2p_mapping[input_port]; 1188 mmu_port = si->port_p2m_mapping[phy_port]; 1189 cpu_sched_base = mmu_port * _BCM_TH3_NUM_SCHEDULER_PER_PORT; 1190 input_cos = cosq % _BCM_TH3_NUM_CPU_MCAST_QUEUE; 1191 input_node->parent_gport = parent_port; 1192 1193 if (BCM_GPORT_IS_SCHEDULER(parent_gport)) { 1194 cpu_mc_base = si->port_cosq_base[CMIC_PORT(unit)]; 1195 parent_cos = (parent_node->hw_index - cpu_sched_base) % 1196 _BCM_TH3_NUM_CPU_MCAST_QUEUE; 1197 SOC_IF_ERROR_RETURN 1198 (soc_th3_cosq_cpu_parent_set(unit, input_cos, SOC_TH3_NODE_LVL_L1, 1199 parent_cos)); 1200 /* 1201 * L0.0 is associated with CMC0 CH1(Rx) 1202 * L0.1 is associated with CMC0 CH2(Rx) 1203 * L0.2 is associated with CMC0 CH3(Rx) 1204 * L0.3 is associated with CMC0 CH4(Rx) 1205 * L0.4 is associated with CMC0 CH5(Rx) 1206 * L0.5 is associated with CMC0 CH6(Rx) 1207 * L0.6 is associated with CMC0 CH7(Rx) 1208 */ 1209 if ((parent_cos >= 0) && (parent_cos < 7)) { 1210 BCM_IF_ERROR_RETURN 1211 (_bcm_th3_cosq_rx_queue_channel_set(unit, parent_cos, input_cos, 1)); 1212 } 1213 input_node->parent_gport = parent_node->gport; 1214 if (_BCM_TH3_MMU_INFO(unit)->gport_tree_created == FALSE) { 1215 input_node->hw_index = cpu_mc_base + input_cos; 1216 } 1217 } else { 1218 input_node->hw_index = cpu_sched_base + input_cos; 1219 } 1220 1221 return BCM_E_NONE; 1222 } 1223 1224 1225 int _bcm_th3_queue_is_unicast(int unit, int queue_num) 1226 { 1227 int mc_q_mode, num_ucq; 1228 1229 mc_q_mode = soc_property_get(unit, spn_MMU_PORT_NUM_MC_QUEUE, _BCM_TH3_MCQ_MODE_DEFAULT); 1230 num_ucq = (mc_q_mode == 0) ? 12 : (mc_q_mode == 1) ? 10 : 1231 (mc_q_mode == 2) ? 8 : (mc_q_mode == 3) ? 6 : 8; 1232 if (queue_num < num_ucq) { 1233 return 1; 1234 } else { 1235 return 0; 1236 } 1237 } 1238 1239 int _bcm_th3_get_num_ucq(int unit) 1240 { 1241 int mc_q_mode, num_ucq; 1242 1243 mc_q_mode = soc_property_get(unit, spn_MMU_PORT_NUM_MC_QUEUE, _BCM_TH3_MCQ_MODE_DEFAULT); 1244 num_ucq = (mc_q_mode == 0) ? 12 : (mc_q_mode == 1) ? 10 : 1245 (mc_q_mode == 2) ? 8 : (mc_q_mode == 3) ? 6 : 8; 1246 1247 return num_ucq; 1248 } 1249 1250 int _bcm_th3_get_num_mcq(int unit) 1251 { 1252 int mc_q_mode, num_mcq; 1253 1254 mc_q_mode = soc_property_get(unit, spn_MMU_PORT_NUM_MC_QUEUE, _BCM_TH3_MCQ_MODE_DEFAULT); 1255 num_mcq = (mc_q_mode == 0) ? 0 : (mc_q_mode == 1) ? 2 : 1256 (mc_q_mode == 2) ? 4 : (mc_q_mode == 3) ? 6 : 4; 1257 1258 return num_mcq; 1259 } 1260 1261 int 1262 _bcm_th3_cosq_port_resolve(int unit, bcm_gport_t gport, bcm_module_t *modid, 1263 bcm_port_t *port, bcm_trunk_t *trunk_id, int *id, 1264 int *qnum) 1265 { 1266 _bcm_th3_cosq_node_t *node; 1267 1268 BCM_IF_ERROR_RETURN 1269 (_bcm_th3_cosq_node_get(unit, gport, modid, port, id, &node)); 1270 *trunk_id = -1; 1271 1272 if (qnum) { 1273 if (node->hw_index == -1) { 1274 return BCM_E_PARAM; 1275 } 1276 *qnum = node->hw_index; 1277 } 1278 1279 return BCM_E_NONE; 1280 } 1281 1282 /* 1283 * Function: 1284 * _bcm_th3_cosq_gport_add_attach 1285 * Purpose: 1286 * Create a cosq gport structure for non CPU Ports 1287 * Parameters: 1288 * unit - (IN) unit number 1289 * port - (IN) port number 1290 * numq - (IN) number of COS queues 1291 * flags - (IN) flags (BCM_COSQ_GPORT_XXX) 1292 * gport - (OUT) GPORT identifier 1293 * Returns: 1294 * BCM_E_XXX 1295 */ 1296 int 1297 _bcm_th3_cosq_gport_add_attach(int unit, bcm_gport_t port, int numq, uint32 flags) 1298 { 1299 _bcm_th3_cosq_port_info_t *port_info = NULL; 1300 uint32 sched_encap; 1301 bcm_port_t local_port; 1302 bcm_gport_t gport; 1303 bcm_gport_t parent_gport; 1304 int id, queue_num; 1305 int modid; 1306 1307 if (_bcm_th3_cosq_port_info[unit] == NULL) { 1308 return BCM_E_INIT; 1309 } 1310 1311 BCM_IF_ERROR_RETURN 1312 (_bcm_th3_cosq_localport_resolve(unit, port, &local_port)); 1313 1314 if (local_port < 0 || IS_LB_PORT(unit, local_port) || IS_CPU_PORT(unit, local_port)) { 1315 return BCM_E_PORT; 1316 } 1317 1318 port_info = &_bcm_th3_cosq_port_info[unit][local_port]; 1319 1320 if (flags == BCM_COSQ_GPORT_SCHEDULER) { 1321 port_info->sched[numq].level = SOC_TH3_NODE_LVL_L0; 1322 port_info->sched[numq].in_use = th3_cosq_mmu_info[unit]->th3_port_info[local_port].L0[numq].in_use; 1323 port_info->sched[numq].hw_index = th3_cosq_mmu_info[unit]->th3_port_info[local_port].L0[numq].hw_index; 1324 port_info->sched[numq].cos = th3_cosq_mmu_info[unit]->th3_port_info[local_port].L0[numq].cos; 1325 port_info->sched[numq].strict_priority = th3_cosq_mmu_info[unit]->th3_port_info[local_port].L0[numq].sched_policy; 1326 port_info->sched[numq].fc_is_uc_only = th3_cosq_mmu_info[unit]->th3_port_info[local_port].L0[numq].fc_is_uc_only; 1327 sched_encap = (numq << 16) | local_port; 1328 BCM_GPORT_SCHEDULER_SET(gport, sched_encap); 1329 port_info->sched[numq].gport = gport; 1330 if (th3_cosq_mmu_info[unit]->th3_port_info[local_port].L0[numq].in_use == 0) 1331 port_info->sched[numq].numq = 0; /* Number of sub-nodes */ 1332 else if ((th3_cosq_mmu_info[unit]->th3_port_info[local_port].L0[numq].children[0] != NULL) && 1333 (th3_cosq_mmu_info[unit]->th3_port_info[local_port].L0[numq].children[1] != NULL)) 1334 port_info->sched[numq].numq = 2; /* Number of sub-nodes */ 1335 else if (th3_cosq_mmu_info[unit]->th3_port_info[local_port].L0[numq].children[0] != NULL) 1336 port_info->sched[numq].numq = 1; /* Number of sub-nodes */ 1337 else 1338 port_info->sched[numq].numq = 0; /* Number of sub-nodes */ 1339 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &modid)); 1340 BCM_GPORT_MODPORT_SET(parent_gport, modid, port); 1341 port_info->sched[numq].parent_gport = parent_gport; 1342 LOG_INFO(BSL_LS_BCM_COSQ, 1343 (BSL_META_U(unit, 1344 "SCHED add_attach port %d numq %d gport %d sched.numq %d\n"), 1345 port, numq, port_info->sched[numq].gport, port_info->sched[numq].numq)); 1346 } else { 1347 id = th3_cosq_mmu_info[unit]->th3_port_info[local_port].mmuq[numq].hw_index; 1348 if (_bcm_th3_queue_is_unicast(unit, id)) { 1349 port_info->ucast[id].level = SOC_TH3_NODE_LVL_L2; 1350 port_info->ucast[id].in_use = 1351 th3_cosq_mmu_info[unit]->th3_port_info[local_port].mmuq[numq].in_use; 1352 if (port_info->ucast[id].in_use) { 1353 port_info->ucast[id].hw_index = 1354 th3_cosq_mmu_info[unit]->th3_port_info[local_port].mmuq[numq].hw_index; 1355 port_info->ucast[id].cos = 1356 th3_cosq_mmu_info[unit]->th3_port_info[local_port].mmuq[numq].parent->parent->cos; 1357 BCM_GPORT_UCAST_QUEUE_GROUP_SYSQID_SET(gport, local_port, id); 1358 port_info->ucast[id].gport = gport; 1359 port_info->ucast[id].numq = 1; 1360 queue_num = 1361 th3_cosq_mmu_info[unit]->th3_port_info[local_port].mmuq[numq].parent->parent->hw_index; 1362 sched_encap = (queue_num << 16) | local_port; 1363 BCM_GPORT_SCHEDULER_SET(parent_gport, sched_encap); 1364 port_info->ucast[id].parent_gport = parent_gport; 1365 LOG_INFO(BSL_LS_BCM_COSQ, 1366 (BSL_META_U(unit, 1367 "UCAST add_attach port %d id %d numq %d gport %d hw_index %d\n"), 1368 port, id, numq, port_info->ucast[id].gport, port_info->ucast[id].hw_index)); 1369 } else { 1370 port_info->ucast[id].numq = 0; 1371 } 1372 } else { 1373 id = id - _bcm_th3_get_num_ucq(unit); 1374 port_info->mcast[id].level = SOC_TH3_NODE_LVL_L2; 1375 port_info->mcast[id].in_use = 1376 th3_cosq_mmu_info[unit]->th3_port_info[local_port].mmuq[numq].in_use; 1377 if (port_info->mcast[id].in_use) { 1378 port_info->mcast[id].hw_index = 1379 th3_cosq_mmu_info[unit]->th3_port_info[local_port].mmuq[numq].hw_index; 1380 port_info->mcast[id].cos = 1381 th3_cosq_mmu_info[unit]->th3_port_info[local_port].mmuq[numq].parent->parent->cos; 1382 BCM_GPORT_MCAST_QUEUE_GROUP_SYSQID_SET(gport, local_port, id); 1383 port_info->mcast[id].gport = gport; 1384 port_info->mcast[id].numq = 1; 1385 queue_num = 1386 th3_cosq_mmu_info[unit]->th3_port_info[local_port].mmuq[numq].parent->parent->hw_index; 1387 sched_encap = (queue_num << 16) | local_port; 1388 BCM_GPORT_SCHEDULER_SET(parent_gport, sched_encap); 1389 port_info->mcast[id].parent_gport = parent_gport; 1390 LOG_INFO(BSL_LS_BCM_COSQ, 1391 (BSL_META_U(unit, 1392 "MCAST add_attach port %d id %d numq %d gport %d hw_index %d\n"), 1393 port, id, numq, gport, port_info->mcast[id].hw_index)); 1394 } else { 1395 port_info->mcast[id].numq = 0; 1396 } 1397 } 1398 } 1399 1400 return BCM_E_NONE; 1401 } 1402 1403 1404 /* 1405 * Function: 1406 * _bcm_th3_cosq_cpu_gport_add_attach 1407 * Purpose: 1408 * Create a cosq gport structure for CPU Ports 1409 * Parameters: 1410 * unit - (IN) unit number 1411 * port - (IN) port number 1412 * numq - (IN) number of COS queues 1413 * flags - (IN) flags (BCM_COSQ_GPORT_XXX) 1414 * gport - (OUT) GPORT identifier 1415 * Returns: 1416 * BCM_E_XXX 1417 */ 1418 int 1419 _bcm_th3_cosq_cpu_gport_add_attach(int unit, bcm_gport_t port, int numq, uint32 flags) 1420 { 1421 _bcm_th3_cosq_cpu_port_info_t *cpu_port_info = NULL; 1422 uint32 sched_encap; 1423 bcm_port_t local_port; 1424 bcm_gport_t gport, parent_gport; 1425 int queue_num; 1426 soc_info_t *si = &SOC_INFO(unit); 1427 1428 if (_bcm_th3_cosq_cpu_port_info[unit] == NULL) { 1429 return BCM_E_INIT; 1430 } 1431 1432 BCM_IF_ERROR_RETURN 1433 (_bcm_th3_cosq_localport_resolve(unit, port, &local_port)); 1434 1435 if (!IS_CPU_PORT(unit, local_port)) { 1436 return BCM_E_PORT; 1437 } 1438 1439 cpu_port_info = &_bcm_th3_cosq_cpu_port_info[unit][local_port]; 1440 1441 if (flags == BCM_COSQ_GPORT_SCHEDULER) { 1442 cpu_port_info->sched[numq].level = SOC_TH3_NODE_LVL_L0; 1443 cpu_port_info->sched[numq].in_use = th3_cosq_mmu_info[unit]->th3_cpu_port_info.L0[numq].in_use; 1444 cpu_port_info->sched[numq].hw_index = th3_cosq_mmu_info[unit]->th3_cpu_port_info.L0[numq].hw_index + 1445 si->port_cosq_base[CMIC_PORT(unit)]; 1446 sched_encap = (numq << 16) | local_port; 1447 BCM_GPORT_SCHEDULER_SET(gport, sched_encap); 1448 cpu_port_info->sched[numq].gport = gport; 1449 cpu_port_info->sched[numq].numq = 4; /* default 4 cos per mmuq*/ 1450 cpu_port_info->sched[numq].parent_gport = port; 1451 LOG_INFO(BSL_LS_BCM_COSQ, 1452 (BSL_META_U(unit, 1453 "cpu_port_info[%d] sched gport=%x parent_gport=%x\n"), 1454 numq, cpu_port_info->sched[numq].gport, cpu_port_info->sched[numq].parent_gport)); 1455 } else { 1456 cpu_port_info->mcast[numq].level = SOC_TH3_NODE_LVL_L1; 1457 cpu_port_info->mcast[numq].in_use = th3_cosq_mmu_info[unit]->th3_cpu_port_info.L1[numq].in_use; 1458 cpu_port_info->mcast[numq].hw_index = th3_cosq_mmu_info[unit]->th3_cpu_port_info.L1[numq].hw_index + 1459 si->port_cosq_base[CMIC_PORT(unit)]; 1460 BCM_GPORT_MCAST_QUEUE_GROUP_SYSQID_SET(gport, local_port, numq); 1461 cpu_port_info->mcast[numq].gport = gport; 1462 cpu_port_info->mcast[numq].numq = 1; 1463 queue_num = th3_cosq_mmu_info[unit]->th3_cpu_port_info.L1[numq].parent->hw_index; 1464 sched_encap = (queue_num << 16) | local_port; 1465 BCM_GPORT_SCHEDULER_SET(parent_gport, sched_encap); 1466 cpu_port_info->mcast[numq].parent_gport = parent_gport; 1467 LOG_INFO(BSL_LS_BCM_COSQ, 1468 (BSL_META_U(unit, 1469 "cpu_port_info[%d] mcast gport=%x parent_gport=%x hw_index=%d\n"), 1470 numq, cpu_port_info->mcast[numq].gport, cpu_port_info->mcast[numq].parent_gport, queue_num)); 1471 } 1472 1473 1474 return BCM_E_NONE; 1475 } 1476 1477 1478 /* 1479 * Function: 1480 * bcm_th3_cosq_gport_add 1481 * Purpose: 1482 * Create a cosq gport structure 1483 * Parameters: 1484 * unit - (IN) unit number 1485 * port - (IN) port number 1486 * numq - (IN) number of COS queues 1487 * flags - (IN) flags (BCM_COSQ_GPORT_XXX) 1488 * gport - (OUT) GPORT identifier 1489 * Returns: 1490 * BCM_E_XXX 1491 */ 1492 int 1493 bcm_th3_cosq_gport_add(int unit, bcm_gport_t port, int numq, uint32 flags, 1494 bcm_gport_t *gport) 1495 { 1496 _bcm_th3_cosq_cpu_port_info_t *cpu_port_info = NULL; 1497 _bcm_th3_cosq_node_t *node; 1498 uint32 sched_encap; 1499 bcm_port_t local_port; 1500 int id = 0; 1501 1502 if (gport == NULL) { 1503 return BCM_E_PARAM; 1504 } 1505 1506 if (_bcm_th3_cosq_cpu_port_info[unit] == NULL) { 1507 return BCM_E_INIT; 1508 } 1509 1510 BCM_IF_ERROR_RETURN 1511 (_bcm_th3_cosq_localport_resolve(unit, port, &local_port)); 1512 1513 if (!IS_CPU_PORT(unit, local_port)) { 1514 return BCM_E_PORT; 1515 } 1516 1517 cpu_port_info = &_bcm_th3_cosq_cpu_port_info[unit][local_port]; 1518 1519 switch (flags) { 1520 case BCM_COSQ_GPORT_UCAST_QUEUE_GROUP: 1521 return BCM_E_PARAM; 1522 case BCM_COSQ_GPORT_MCAST_QUEUE_GROUP: 1523 if (numq != 1) { 1524 return BCM_E_PARAM; 1525 } 1526 if (IS_CPU_PORT(unit, local_port)) { 1527 for (id = 0; id < _BCM_TH3_NUM_CPU_MCAST_QUEUE; id++) { 1528 if ((cpu_port_info->mcast[id].numq == 0) || 1529 (cpu_port_info->mcast[id].in_use == 0)) { 1530 break; 1531 } 1532 } 1533 if (id == _BCM_TH3_NUM_CPU_MCAST_QUEUE) { 1534 return BCM_E_RESOURCE; 1535 } 1536 } 1537 BCM_GPORT_MCAST_QUEUE_GROUP_SYSQID_SET(*gport, local_port, id); 1538 node = &cpu_port_info->mcast[id]; 1539 node->level = SOC_TH3_NODE_LVL_L1; 1540 break; 1541 case BCM_COSQ_GPORT_SCHEDULER: 1542 if (numq <= 0) { 1543 return BCM_E_PARAM; 1544 } 1545 for (id = 0; id < _BCM_TH3_NUM_SCHEDULER_PER_PORT; id++) { 1546 if (IS_CPU_PORT(unit, local_port)) { 1547 if (cpu_port_info->sched[id].numq == 0) { 1548 break; 1549 } 1550 } 1551 } 1552 if (id == _BCM_TH3_NUM_SCHEDULER_PER_PORT) { 1553 return BCM_E_RESOURCE; 1554 } 1555 1556 sched_encap = (id << 16) | local_port; 1557 BCM_GPORT_SCHEDULER_SET(*gport, sched_encap); 1558 node = &cpu_port_info->sched[id]; 1559 node->level = SOC_TH3_NODE_LVL_L0; 1560 break; 1561 default: 1562 return BCM_E_UNAVAIL; 1563 } 1564 1565 node->gport = *gport; 1566 node->numq = numq; 1567 node->in_use = 1; 1568 1569 return BCM_E_NONE; 1570 } 1571 1572 int 1573 _bcm_th3_cosq_gport_hw_delete(int unit, int schedq, int L0) 1574 { 1575 soc_reg_t reg = INVALIDr; 1576 uint32 rval; 1577 1578 reg = MMU_MTRO_CPU_L1_TO_L0_MAPPINGr; 1579 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, reg, REG_PORT_ANY, schedq, &rval)); 1580 soc_reg_field_set(unit, reg, &rval, SELECTf, L0); 1581 SOC_IF_ERROR_RETURN 1582 (soc_reg32_set(unit, reg, REG_PORT_ANY, schedq, rval)); 1583 1584 reg = MMU_QSCH_CPU_L1_TO_L0_MAPPINGr; 1585 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, reg, REG_PORT_ANY, schedq, &rval)); 1586 soc_reg_field_set(unit, reg, &rval, SELECTf, L0); 1587 SOC_IF_ERROR_RETURN 1588 (soc_reg32_set(unit, reg, REG_PORT_ANY, schedq, rval)); 1589 1590 return BCM_E_NONE; 1591 } 1592 1593 int 1594 bcm_th3_cosq_gport_delete(int unit, bcm_gport_t gport) 1595 { 1596 _bcm_th3_cosq_node_t *node = NULL; 1597 _bcm_th3_cosq_node_t *child_node = NULL; 1598 _bcm_th3_cosq_cpu_port_info_t *cpu_port_info = NULL; 1599 int local_port, i, j; 1600 1601 if (_bcm_th3_cosq_cpu_port_info[unit] == NULL) { 1602 return BCM_E_INIT; 1603 } 1604 1605 BCM_IF_ERROR_RETURN 1606 (_bcm_th3_cosq_localport_resolve(unit, gport, &local_port)); 1607 1608 if (!IS_CPU_PORT(unit, local_port)) { 1609 return BCM_E_PORT; 1610 } 1611 1612 1613 LOG_INFO(BSL_LS_BCM_COSQ, 1614 (BSL_META_U(unit, 1615 "bcm_th3_cosq_gport_delete: unit=%d gport=0x%x\n"), 1616 unit, gport)); 1617 1618 /* Note: currently resets mapping to resetvalue of 0*/ 1619 if (BCM_GPORT_IS_SCHEDULER(gport) || 1620 BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 1621 BCM_IF_ERROR_RETURN 1622 (_bcm_th3_cosq_node_get(unit, gport, NULL, NULL, NULL, &node)); 1623 1624 cpu_port_info = &_bcm_th3_cosq_cpu_port_info[unit][local_port]; 1625 if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 1626 for (i = 0; i < _BCM_TH3_NUM_CPU_MCAST_QUEUE; i++) { 1627 if (cpu_port_info->mcast[i].gport == gport) { 1628 node = &cpu_port_info->mcast[i]; 1629 if (node->in_use == 0) { 1630 return BCM_E_UNAVAIL; 1631 } 1632 BCM_IF_ERROR_RETURN 1633 (_bcm_th3_cosq_gport_hw_delete(unit, i, 0)); 1634 node->in_use = 0; 1635 node->numq = 0; 1636 node->parent_gport = 0; 1637 } 1638 } 1639 } else if (BCM_GPORT_IS_SCHEDULER(gport)) { 1640 for (i = 0; i < _BCM_TH3_NUM_SCHEDULER_PER_PORT; i++) { 1641 if (cpu_port_info->sched[i].gport == gport) { 1642 node = &cpu_port_info->sched[i]; 1643 if (node->in_use == 0) { 1644 return BCM_E_UNAVAIL; 1645 } 1646 node->in_use = 0; 1647 node->numq = 0; 1648 node->parent_gport = 0; 1649 } 1650 for (j = 0; j < _BCM_TH3_NUM_CPU_MCAST_QUEUE; j++) { 1651 if (cpu_port_info->mcast[i].parent_gport == gport) { 1652 child_node = &cpu_port_info->mcast[i]; 1653 child_node->in_use = 0; 1654 child_node->numq = 0; 1655 child_node->parent_gport = 0; 1656 BCM_IF_ERROR_RETURN 1657 (_bcm_th3_cosq_gport_hw_delete(unit, j, 0)); 1658 } 1659 } 1660 } 1661 } 1662 } else { 1663 return BCM_E_PARAM; 1664 } 1665 1666 return BCM_E_NONE; 1667 } 1668 1669 /* Function: 1670 * bcm_th3_cosq_config_get 1671 * Purpose: 1672 * Get the number of cos queues 1673 * Parameters: 1674 * unit - unit number 1675 * numq - (Output) number of cosq 1676 * Returns: 1677 * BCM_E_XXX 1678 */ 1679 int 1680 bcm_th3_cosq_config_get(int unit, int *numq) 1681 { 1682 int prio, max_cos = 0; 1683 soc_mem_t mem = PORT_COS_MAPm; 1684 uint32 entry[SOC_MAX_MEM_WORDS]; 1685 1686 if (numq == NULL) { 1687 return BCM_E_MEMORY; 1688 } 1689 1690 /* Read profile0 of PORT_COS_MAP to get the max number of COS */ 1691 for (prio = 0; prio < _TH3_MMU_NUM_INT_PRI; prio++) { 1692 SOC_IF_ERROR_RETURN 1693 (soc_mem_read(unit, mem, MEM_BLOCK_ALL, prio, entry)); 1694 max_cos = MAX(max_cos, soc_mem_field32_get(unit, mem, entry, UC_COS1f)); 1695 1696 } 1697 *numq = (max_cos + 1); 1698 1699 return BCM_E_NONE; 1700 } 1701 1702 int 1703 bcm_th3_cosq_config_set(int unit, int numq) 1704 { 1705 port_cos_map_entry_t cos_map_entries[_TH3_MMU_NUM_INT_PRI]; 1706 void *entries[1]; 1707 uint32 index; 1708 int count, i; 1709 bcm_port_t port; 1710 int cos, prio, ref_count = -1; 1711 soc_mem_t mem = INVALIDm; 1712 int num_ucq, num_mcq, num_rqe; 1713 uint16 dev_id; 1714 uint8 rev_id; 1715 1716 if (numq < 1 || numq > _BCM_TH3_COS_MAX) { 1717 return BCM_E_PARAM; 1718 } 1719 1720 num_ucq = _bcm_th3_get_num_ucq(unit); 1721 if (numq > num_ucq) { 1722 return BCM_E_PARAM; 1723 } 1724 num_mcq = _bcm_th3_get_num_mcq(unit); 1725 1726 soc_cm_get_id(unit, &dev_id, &rev_id); 1727 if (rev_id == BCM56980_A0_REV_ID) { 1728 num_rqe = 1; 1729 } else { 1730 num_rqe = num_mcq; 1731 } 1732 1733 index = 0; 1734 while (index < soc_mem_index_count(unit, PORT_COS_MAPm)) { 1735 BCM_IF_ERROR_RETURN(soc_profile_mem_ref_count_get(unit, 1736 _bcm_th3_cos_map_profile[unit], 1737 index, &ref_count)); 1738 if (ref_count > 0) { 1739 while (ref_count) { 1740 if (!soc_profile_mem_delete(unit, 1741 _bcm_th3_cos_map_profile[unit], index)) { 1742 ref_count -= 1; 1743 } 1744 } 1745 } 1746 index += _TH3_MMU_NUM_INT_PRI; 1747 } 1748 1749 /* Distribute first 8 internal priority levels into the specified number 1750 * of cosq, map remaining internal priority levels to highest priority 1751 * cosq */ 1752 sal_memset(cos_map_entries, 0, sizeof(cos_map_entries)); 1753 entries[0] = &cos_map_entries; 1754 prio = 0; 1755 mem = PORT_COS_MAPm; 1756 1757 for (cos = 0; cos < numq; cos++) { 1758 soc_mem_field32_set(unit, mem, &cos_map_entries[prio], 1759 UC_COS1f, MIN(cos, num_ucq - 1)); 1760 soc_mem_field32_set(unit, mem, &cos_map_entries[prio], 1761 UC_COS2f, MIN(cos, num_ucq - 1)); 1762 soc_mem_field32_set(unit, mem, &cos_map_entries[prio], 1763 MC_COS1f, MIN(cos, num_mcq ? num_mcq - 1 : 0)); 1764 soc_mem_field32_set(unit, mem, &cos_map_entries[prio], 1765 RQE_Q_NUMf, MIN(cos, num_rqe ? num_rqe - 1 : 0)); 1766 prio++; 1767 } 1768 for (; prio < _TH3_MMU_NUM_INT_PRI; prio++) { 1769 if (prio < numq) { 1770 soc_mem_field32_set(unit, mem, &cos_map_entries[prio], UC_COS1f, 1771 MIN(prio, num_ucq - 1)); 1772 soc_mem_field32_set(unit, mem, &cos_map_entries[prio], UC_COS2f, 1773 MIN(prio, num_ucq - 1)); 1774 soc_mem_field32_set(unit, mem, &cos_map_entries[prio], MC_COS1f, 1775 MIN(prio, num_mcq ? num_mcq - 1 : 0)); 1776 soc_mem_field32_set(unit, mem, &cos_map_entries[prio], RQE_Q_NUMf, 1777 MIN(prio, num_rqe ? num_rqe - 1 : 0)); 1778 } 1779 else { 1780 soc_mem_field32_set(unit, mem, &cos_map_entries[prio], UC_COS1f, 1781 MIN(numq - 1, num_ucq - 1)); 1782 soc_mem_field32_set(unit, mem, &cos_map_entries[prio], UC_COS2f, 1783 MIN(numq - 1, num_ucq - 1)); 1784 soc_mem_field32_set(unit, mem, &cos_map_entries[prio], MC_COS1f, 1785 MIN(numq - 1, num_mcq ? num_mcq - 1 : 0)); 1786 soc_mem_field32_set(unit, mem, &cos_map_entries[prio], RQE_Q_NUMf, 1787 MIN(numq - 1, num_rqe ? num_rqe - 1 : 0)); 1788 } 1789 } 1790 1791 /* Map internal priority levels to CPU CoS queues */ 1792 BCM_IF_ERROR_RETURN(_bcm_esw_cpu_cosq_mapping_default_set(unit, numq)); 1793 1794 BCM_IF_ERROR_RETURN 1795 (soc_profile_mem_add(unit, _bcm_th3_cos_map_profile[unit], entries, 1796 _TH3_MMU_NUM_INT_PRI, &index)); 1797 count = 0; 1798 PBMP_ALL_ITER(unit, port) { 1799 BCM_IF_ERROR_RETURN 1800 (soc_mem_field32_modify(unit, COS_MAP_SELm, port, SELECTf, 1801 index / _TH3_MMU_NUM_INT_PRI)); 1802 count++; 1803 } 1804 if (SOC_INFO(unit).cpu_hg_index != -1) { 1805 BCM_IF_ERROR_RETURN 1806 (soc_mem_field32_modify(unit, COS_MAP_SELm, 1807 SOC_INFO(unit).cpu_hg_index, SELECTf, 1808 index / _TH3_MMU_NUM_INT_PRI)); 1809 count++; 1810 } 1811 for (i = 1; i < count; i++) { 1812 soc_profile_mem_reference(unit, _bcm_th3_cos_map_profile[unit], index, 1813 0); 1814 } 1815 1816 _TH3_NUM_COS(unit) = SOC_TH3_COS_MAX; 1817 1818 return BCM_E_NONE; 1819 } 1820 1821 /* 1822 * Function: 1823 * bcm_th3_cosq_gport_attach 1824 * Purpose: 1825 * Attach sched_port to the specified index (cosq) of input_port (CPU Port only) 1826 * Parameters: 1827 * unit - (IN) unit number 1828 * input_gport - (IN) GPORT id, that will attach to parent gport 1829 * parent_gport - (IN) Parent Gport to which current gport will be attached 1830 * cosq - (IN) COS queue to attach to (-1 for first available cosq) 1831 * Returns: 1832 * BCM_E_XXX 1833 */ 1834 int 1835 bcm_th3_cosq_gport_attach(int unit, bcm_gport_t input_gport, 1836 bcm_gport_t parent_gport, bcm_cos_queue_t cosq) 1837 { 1838 _bcm_th3_cosq_node_t *input_node = NULL; 1839 bcm_port_t input_port; 1840 1841 LOG_INFO(BSL_LS_BCM_COSQ, 1842 (BSL_META_U(unit, 1843 "bcm_th3_cosq_gport_attach: unit=%d parent_gport=0x%x " 1844 "input_gport=0x%x cosq=%d\n"), 1845 unit, parent_gport, input_gport, cosq)); 1846 1847 if (!(BCM_GPORT_IS_SCHEDULER(input_gport) || 1848 BCM_GPORT_IS_UCAST_QUEUE_GROUP(input_gport) || 1849 BCM_GPORT_IS_MCAST_QUEUE_GROUP(input_gport))) { 1850 return BCM_E_PARAM; 1851 } 1852 1853 BCM_IF_ERROR_RETURN 1854 (_bcm_th3_cosq_node_get(unit, input_gport, NULL, &input_port, NULL, 1855 &input_node)); 1856 1857 if (!input_node) { 1858 return BCM_E_PARAM; 1859 } 1860 if (input_port < 0) { 1861 return BCM_E_PORT; 1862 } 1863 1864 if (!IS_CPU_PORT(unit, input_port)) { 1865 return BCM_E_PORT; 1866 } 1867 BCM_IF_ERROR_RETURN 1868 (bcm_th3_cosq_cpu_gport_attach(unit, input_gport, 1869 parent_gport, cosq)); 1870 1871 return BCM_E_NONE; 1872 } 1873 1874 /* Function to detach any of the 48 L1 MC Queue from its parent 12 L0 nodes 1875 * Post detach, L1 MC queue is attached to Parent L0.11 node 1876 */ 1877 STATIC int 1878 bcm_th3_cosq_cpu_gport_detach(int unit, bcm_gport_t input_gport, 1879 bcm_gport_t parent_gport, bcm_cos_queue_t cosq) 1880 { 1881 bcm_port_t parent_port, input_port; 1882 _bcm_th3_cosq_node_t *input_node = NULL, *parent_node = NULL; 1883 int phy_port, mmu_port; 1884 int input_cos = 0, parent_cos = 0, config_cos = 0; 1885 int cpu_mc_base = 0, cpu_sched_base = 0; 1886 soc_info_t *si = &SOC_INFO(unit); 1887 1888 /* Post Default tree created, expected Input Gport is of MC Gport 1889 * and expected Parent Gport is new L0 Parent 1890 */ 1891 if ((!BCM_GPORT_IS_SCHEDULER(parent_gport)) || 1892 (!BCM_GPORT_IS_MCAST_QUEUE_GROUP(input_gport))) { 1893 return BCM_E_PARAM; 1894 } 1895 BCM_IF_ERROR_RETURN 1896 (_bcm_th3_cosq_node_get(unit, input_gport, NULL, &input_port, NULL, 1897 &input_node)); 1898 BCM_IF_ERROR_RETURN 1899 (_bcm_th3_cosq_node_get(unit, parent_gport, NULL, &parent_port, NULL, 1900 &parent_node)); 1901 1902 if (!IS_CPU_PORT(unit, parent_port)) { 1903 return BCM_E_PORT; 1904 } 1905 1906 /* Return BCM_E_PARAM when queue to be detached is 1907 not attached to the given gport */ 1908 if (input_node->parent_gport != parent_gport) { 1909 return BCM_E_PARAM; 1910 } 1911 1912 phy_port = si->port_l2p_mapping[input_port]; 1913 mmu_port = si->port_p2m_mapping[phy_port]; 1914 cpu_sched_base = mmu_port * _BCM_TH3_NUM_SCHEDULER_PER_PORT; 1915 parent_cos = (parent_node->hw_index - cpu_sched_base) % 1916 _BCM_TH3_NUM_CPU_MCAST_QUEUE; 1917 cpu_mc_base = si->port_cosq_base[CMIC_PORT(unit)]; 1918 input_cos = (input_node->hw_index - cpu_mc_base) % 1919 _BCM_TH3_NUM_CPU_MCAST_QUEUE; 1920 1921 /* Reset parent to L0.11 */ 1922 SOC_IF_ERROR_RETURN 1923 (soc_th3_cosq_cpu_parent_get(unit, input_cos, SOC_TH3_NODE_LVL_L1, 1924 &config_cos)); 1925 if (config_cos != parent_cos) { 1926 /* Error when detaching from wrong Parent (L0 level) */ 1927 return BCM_E_PARAM; 1928 } 1929 1930 /* 1931 * L0.0 is associated with CMC0 CH1(Rx) 1932 * L0.1 is associated with CMC0 CH2(Rx) 1933 * L0.2 is associated with CMC0 CH3(Rx) 1934 * L0.3 is associated with CMC0 CH4(Rx) 1935 * L0.4 is associated with CMC0 CH5(Rx) 1936 * L0.5 is associated with CMC0 CH6(Rx) 1937 * L0.6 is associated with CMC0 CH7(Rx) 1938 */ 1939 if ((parent_cos >= 0) && (parent_cos < 7)) { 1940 BCM_IF_ERROR_RETURN 1941 (_bcm_th3_cosq_rx_queue_channel_set(unit, parent_cos, input_cos, 0)); 1942 } 1943 1944 /* Reset parent to L0.11 */ 1945 SOC_IF_ERROR_RETURN 1946 (soc_th3_cosq_cpu_parent_set(unit, input_cos, SOC_TH3_NODE_LVL_L1, 1947 _BCM_TH3_NUM_SCHEDULER_PER_PORT-1)); 1948 input_node->parent_gport = 1949 _BCM_TH3_MMU_INFO(unit)->_bcm_th3_cpu_port_info-> 1950 sched[_BCM_TH3_NUM_SCHEDULER_PER_PORT-1].gport; 1951 1952 return BCM_E_NONE; 1953 } 1954 1955 /* 1956 * Function: 1957 * bcm_th3_cosq_gport_detach 1958 * Purpose: 1959 * Detach sched_port from the specified index (cosq) of input_port (only CPU Port) 1960 * Parameters: 1961 * unit - (IN) unit number 1962 * sched_port - (IN) scheduler GPORT identifier 1963 * input_port - (IN) GPORT to detach from 1964 * cosq - (IN) COS queue to detach from 1965 * Returns: 1966 * BCM_E_XXX 1967 */ 1968 int 1969 bcm_th3_cosq_gport_detach(int unit, bcm_gport_t input_gport, 1970 bcm_gport_t parent_gport, bcm_cos_queue_t cosq) 1971 { 1972 _bcm_th3_cosq_node_t *input_node = NULL; 1973 bcm_port_t input_port; 1974 1975 LOG_INFO(BSL_LS_BCM_COSQ, 1976 (BSL_META_U(unit, 1977 "bcm_th3_cosq_gport_detach: unit=%d input_gport=0x%x " 1978 "parent_gport=0x%x cosq=%d\n"), 1979 unit, input_gport, parent_gport, cosq)); 1980 1981 if (!(BCM_GPORT_IS_SCHEDULER(input_gport) || 1982 BCM_GPORT_IS_UCAST_QUEUE_GROUP(input_gport) || 1983 BCM_GPORT_IS_MCAST_QUEUE_GROUP(input_gport))) { 1984 return BCM_E_PARAM; 1985 } 1986 1987 BCM_IF_ERROR_RETURN 1988 (_bcm_th3_cosq_node_get(unit, input_gport, NULL, &input_port, NULL, 1989 &input_node)); 1990 1991 if (!input_node) { 1992 return BCM_E_PARAM; 1993 } 1994 1995 if (!IS_CPU_PORT(unit, input_port)) { 1996 return BCM_E_PORT; 1997 } 1998 1999 if (_BCM_TH3_MMU_INFO(unit)->gport_tree_created == TRUE) { 2000 return bcm_th3_cosq_cpu_gport_detach(unit, input_gport, 2001 parent_gport, cosq); 2002 } else { 2003 return BCM_E_INIT; 2004 } 2005 2006 } 2007 2008 /* 2009 * Function: 2010 * bcm_th3_cosq_gport_child_get 2011 * Purpose: 2012 * Get the child node GPORT atatched to N-th index (cosq). Only CPu PORT 2013 * of the scheduler GPORT. 2014 * Parameters: 2015 * unit - (IN) Unit number. 2016 * in_gport - (IN) Scheduler GPORT ID. 2017 * cosq - (IN) COS queue attached to. 2018 * out_gport - (OUT) child GPORT ID. 2019 * Returns: 2020 * BCM_E_XXX 2021 * Notes: 2022 */ 2023 int 2024 bcm_th3_cosq_gport_child_get(int unit, bcm_gport_t in_gport, 2025 bcm_cos_queue_t cosq, 2026 bcm_gport_t *out_gport) 2027 { 2028 _bcm_th3_cosq_node_t *tmp_node = NULL; 2029 bcm_port_t local_port = -1; 2030 _bcm_th3_cosq_cpu_port_info_t *cpu_port_info = NULL; 2031 _bcm_th3_cosq_port_info_t *port_info = NULL; 2032 int index = -1, cpu_mc_base = 0; 2033 soc_info_t *si = &SOC_INFO(unit); 2034 2035 if (out_gport == NULL) { 2036 return BCM_E_PARAM; 2037 } 2038 2039 BCM_IF_ERROR_RETURN 2040 (_bcm_th3_cosq_localport_resolve(unit, in_gport, &local_port)); 2041 2042 if (!SOC_PORT_VALID(unit, local_port)) { 2043 return BCM_E_PORT; 2044 } 2045 2046 if (IS_CPU_PORT(unit, local_port)) { 2047 if ((cosq < 0) || (cosq >= NUM_CPU_COSQ(unit))) { 2048 return BCM_E_PARAM; 2049 } 2050 2051 if (_bcm_th3_cosq_cpu_port_info[unit] == NULL) { 2052 return BCM_E_INIT; 2053 } 2054 2055 cpu_port_info = _bcm_th3_cosq_cpu_port_info[unit]; 2056 cpu_mc_base = si->port_cosq_base[CMIC_PORT(unit)]; 2057 2058 if (BCM_GPORT_IS_SCHEDULER(in_gport)) { 2059 for (index = 0; index < _BCM_TH3_NUM_CPU_MCAST_QUEUE; index++) { 2060 if (cpu_port_info->mcast[index].parent_gport == in_gport) { 2061 if (cosq == ((cpu_port_info->mcast[index].hw_index - cpu_mc_base) % 2062 _BCM_TH3_NUM_CPU_MCAST_QUEUE)) { 2063 tmp_node = &cpu_port_info->mcast[index]; 2064 *out_gport = tmp_node->gport; 2065 goto exit; 2066 } 2067 } 2068 } 2069 } else { 2070 return BCM_E_PARAM; 2071 } 2072 2073 if (tmp_node == NULL) { 2074 return BCM_E_NOT_FOUND; 2075 } 2076 2077 } else { /* Non-CPU port */ 2078 if (_bcm_th3_cosq_port_info[unit] == NULL) { 2079 return BCM_E_INIT; 2080 } 2081 if ((cosq < 0) || (cosq >= _BCM_TH3_COS_MAX)) { 2082 return BCM_E_PARAM; 2083 } 2084 port_info = &_bcm_th3_cosq_port_info[unit][local_port]; 2085 2086 if (BCM_GPORT_IS_SCHEDULER(in_gport)) { 2087 for (index = 0; index < _BCM_TH3_MAX_NUM_UCAST_QUEUE_PER_PORT; index++) { 2088 if (port_info->ucast[index].parent_gport == in_gport) { 2089 if (cosq == (port_info->ucast[index].cos % 2090 _BCM_TH3_COS_MAX)) { 2091 tmp_node = &port_info->ucast[index]; 2092 *out_gport = tmp_node->gport; 2093 goto exit; 2094 } 2095 } 2096 } 2097 if (tmp_node == NULL) { 2098 for (index = 0; index < _BCM_TH3_MAX_NUM_MCAST_QUEUE_PER_PORT; index++) { 2099 if (port_info->mcast[index].parent_gport == in_gport) { 2100 if (cosq == (port_info->mcast[index].cos % 2101 _BCM_TH3_COS_MAX)) { 2102 tmp_node = &port_info->mcast[index]; 2103 *out_gport = tmp_node->gport; 2104 goto exit; 2105 } 2106 } 2107 } 2108 } 2109 } else { 2110 return BCM_E_PARAM; 2111 } 2112 2113 if (tmp_node == NULL) { 2114 return BCM_E_NOT_FOUND; 2115 } 2116 } 2117 2118 exit: 2119 return BCM_E_NONE; 2120 } 2121 2122 2123 /* 2124 * Function: 2125 * bcm_th3_cosq_gport_sched_get 2126 * Purpose: 2127 * Get COS queue schedular setting 2128 * Parameters: 2129 * unit - (IN) unit number 2130 * gport - (IN) GPORT identifier 2131 * cosq - (IN) COS queue to get, -1 for any queue 2132 * mode - (OUT) Scheduling mode (BCM_COSQ_XXX) 2133 * weights - (OUT) Weights for queue 2134 * Returns: 2135 * BCM_E_XXX 2136 */ 2137 int 2138 bcm_th3_cosq_gport_sched_get(int unit, bcm_gport_t gport, 2139 bcm_cos_queue_t cosq, int *mode, int *weight) 2140 { 2141 _bcm_th3_cosq_node_t *node = NULL; 2142 int local_port = -1, cpu_mc_base = 0; 2143 soc_info_t *si = &SOC_INFO(unit); 2144 2145 if (BCM_GPORT_IS_SET(gport)) { 2146 if ((BCM_GPORT_IS_SCHEDULER(gport)) || 2147 BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport) || 2148 BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 2149 2150 BCM_IF_ERROR_RETURN 2151 (_bcm_th3_cosq_node_get(unit, gport, NULL, &local_port, NULL, &node)); 2152 2153 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 2154 /* For Non-CPU and non-LB ports, num UC queues are 10 */ 2155 cosq = node->hw_index % _BCM_TH3_MAX_NUM_QUEUE_PER_PORT; 2156 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 2157 /* For Non-CPU ports, num MC queues are 10 2158 * For CPU ports, num MC queues are 48 2159 */ 2160 if (IS_CPU_PORT(unit, local_port)) { 2161 cpu_mc_base = si->port_cosq_base[CMIC_PORT(unit)]; 2162 cosq = (node->hw_index - cpu_mc_base) % 2163 _BCM_TH3_NUM_CPU_MCAST_QUEUE; 2164 } else { 2165 cosq = node->hw_index % _BCM_TH3_MAX_NUM_QUEUE_PER_PORT; 2166 } 2167 } else { 2168 /* For all ports, total scheduler nodes(L0) are 12 */ 2169 cosq = node->hw_index % _BCM_TH3_NUM_SCHEDULER_PER_PORT; 2170 } 2171 BCM_IF_ERROR_RETURN( 2172 _bcm_th3_cosq_sched_get(unit, gport, cosq, mode, weight)); 2173 return BCM_E_NONE; 2174 } else { 2175 BCM_IF_ERROR_RETURN(_bcm_th3_cosq_localport_resolve(unit, gport, 2176 &local_port)); 2177 2178 if ((cosq < 0) || (cosq >= _TH3_PORT_NUM_COS(unit, local_port))) { 2179 return BCM_E_PARAM; 2180 } 2181 2182 BCM_IF_ERROR_RETURN( 2183 _bcm_th3_cosq_sched_get(unit, local_port, cosq, mode, weight)); 2184 return BCM_E_NONE; 2185 } 2186 } else { 2187 return BCM_E_PORT; 2188 } 2189 2190 return BCM_E_NOT_FOUND; 2191 } 2192 2193 /* 2194 * Function: 2195 * bcm_th3_cosq_gport_sched_set 2196 * Purpose: 2197 * Set up class-of-service policy and corresponding weights and delay 2198 * Parameters: 2199 * unit - (IN) unit number 2200 * gport - (IN) GPORT ID 2201 * cosq - (IN) COS queue to configure 2202 * mode - (IN) Scheduling mode (BCM_COSQ_xxx) 2203 * weight - (IN) Weight for COS queue 2204 * Returns: 2205 * BCM_E_XXX 2206 */ 2207 int 2208 bcm_th3_cosq_gport_sched_set(int unit, bcm_gport_t gport, 2209 bcm_cos_queue_t cosq, int mode, int weight) 2210 { 2211 _bcm_th3_cosq_node_t *node = NULL; 2212 soc_info_t *si = &SOC_INFO(unit); 2213 int local_port = -1, cpu_mc_base = 0; 2214 2215 if (BCM_GPORT_IS_SET(gport)) { 2216 if (BCM_GPORT_IS_SCHEDULER(gport) || 2217 BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport) || 2218 BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 2219 2220 BCM_IF_ERROR_RETURN 2221 (_bcm_th3_cosq_node_get(unit, gport, NULL, &local_port, 2222 NULL, &node)); 2223 2224 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 2225 /* For Non-CPU and non-LB ports, num UC queues are 12 */ 2226 cosq = node->hw_index % _BCM_TH3_MAX_NUM_QUEUE_PER_PORT; 2227 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 2228 /* For Non-CPU ports, num MC queues are 12 2229 * For CPU ports, num MC queues are 48 2230 */ 2231 if (IS_CPU_PORT(unit, local_port)) { 2232 cpu_mc_base = si->port_cosq_base[CMIC_PORT(unit)]; 2233 cosq = (node->hw_index - cpu_mc_base) % 2234 _BCM_TH3_NUM_CPU_MCAST_QUEUE; 2235 } else { 2236 cosq = node->hw_index % _BCM_TH3_MAX_NUM_QUEUE_PER_PORT; 2237 } 2238 } else { 2239 /* For all ports, total scheduler nodes(L0) are 10 */ 2240 cosq = node->hw_index % _BCM_TH3_NUM_SCHEDULER_PER_PORT; 2241 } 2242 BCM_IF_ERROR_RETURN 2243 (_bcm_th3_cosq_sched_set(unit, gport, cosq, mode, weight)); 2244 return BCM_E_NONE; 2245 } else { 2246 BCM_IF_ERROR_RETURN(_bcm_th3_cosq_localport_resolve(unit, gport, 2247 &local_port)); 2248 2249 if ((cosq < 0) || (cosq >= _TH3_PORT_NUM_COS(unit, local_port))) { 2250 return BCM_E_PARAM; 2251 } 2252 2253 BCM_IF_ERROR_RETURN 2254 (_bcm_th3_cosq_sched_set(unit, local_port, cosq, mode, weight)); 2255 return BCM_E_NONE; 2256 } 2257 } else { 2258 return BCM_E_PORT; 2259 } 2260 2261 return BCM_E_NOT_FOUND; 2262 } 2263 2264 /* 2265 * Function: 2266 * bcm_th3_cosq_init 2267 * Purpose: 2268 * Initialize (clear) all COS schedule/mapping state. 2269 * Parameters: 2270 * unit - unit number 2271 * Returns: 2272 * BCM_E_XXX 2273 */ 2274 int 2275 bcm_th3_cosq_init(int unit) 2276 { 2277 STATIC int _th3_max_cosq = -1; 2278 int i, alloc_size; 2279 int pipe = -1, itm = -1; 2280 uint32 pipe_map; 2281 bcm_port_t port; 2282 soc_mem_t mem = INVALIDm; 2283 static soc_mem_t wred_mems[_BCM_TH3_NUM_WRED_PROFILES] = { 2284 MMU_WRED_DROP_CURVE_PROFILE_0_0m, MMU_WRED_DROP_CURVE_PROFILE_1_0m, 2285 MMU_WRED_DROP_CURVE_PROFILE_2_0m, MMU_WRED_DROP_CURVE_PROFILE_3_0m, 2286 MMU_WRED_DROP_CURVE_PROFILE_4_0m, MMU_WRED_DROP_CURVE_PROFILE_5_0m, 2287 MMU_WRED_DROP_CURVE_PROFILE_6_0m, MMU_WRED_DROP_CURVE_PROFILE_7_0m, 2288 MMU_WRED_DROP_CURVE_PROFILE_8_0m 2289 }; 2290 int entry_words[_BCM_TH3_NUM_WRED_PROFILES]; 2291 mmu_wred_drop_curve_profile_0_entry_t entry_tcp_green; 2292 mmu_wred_drop_curve_profile_1_entry_t entry_tcp_yellow; 2293 mmu_wred_drop_curve_profile_2_entry_t entry_tcp_red; 2294 mmu_wred_drop_curve_profile_3_entry_t entry_nontcp_green; 2295 mmu_wred_drop_curve_profile_4_entry_t entry_nontcp_yellow; 2296 mmu_wred_drop_curve_profile_5_entry_t entry_nontcp_red; 2297 mmu_wred_drop_curve_profile_6_entry_t entry_ecn_green; 2298 mmu_wred_drop_curve_profile_7_entry_t entry_ecn_yellow; 2299 mmu_wred_drop_curve_profile_8_entry_t entry_ecn_red; 2300 void *entries[_BCM_TH3_NUM_WRED_PROFILES]; 2301 int wred_prof_count; 2302 soc_mem_t wred_config_mem = INVALIDm; 2303 uint32 profile_index; 2304 uint32 entry[SOC_MAX_MEM_WORDS]; 2305 int min_index, max_index; 2306 int num_uc_q; 2307 2308 _bcm_bst_device_handlers_t bst_callbks; 2309 2310 _bcm_th3_cosq_cpu_cosq_config_t *cpu_cosq_config_p = NULL; 2311 int rv = BCM_E_NONE; 2312 2313 if (_th3_max_cosq < 0) { 2314 _th3_max_cosq = NUM_COS(unit); 2315 NUM_COS(unit) = 12; 2316 } 2317 2318 sal_memset(&entry, 0, sizeof(entry)); 2319 2320 if (!SOC_WARM_BOOT(unit)) { 2321 _bcm_th3_cosq_cleanup(unit); 2322 } 2323 2324 2325 /* Create Port Information structure */ 2326 alloc_size = sizeof(_bcm_th3_cosq_port_info_t) * SOC_TH3_MAX_NUM_PORTS; 2327 if (_bcm_th3_cosq_port_info[unit] == NULL) { 2328 _bcm_th3_cosq_port_info[unit] = 2329 sal_alloc(alloc_size, "_bcm_th3_cosq_port_info"); 2330 if (_bcm_th3_cosq_port_info[unit] == NULL) { 2331 return BCM_E_MEMORY; 2332 } 2333 } 2334 sal_memset(_bcm_th3_cosq_port_info[unit], 0, alloc_size); 2335 2336 /* Create CPU Port Information structure */ 2337 alloc_size = sizeof(_bcm_th3_cosq_cpu_port_info_t); 2338 if (_bcm_th3_cosq_cpu_port_info[unit] == NULL) { 2339 _bcm_th3_cosq_cpu_port_info[unit] = 2340 sal_alloc(alloc_size, "_bcm_th3_cosq_cpu_port_info"); 2341 if (_bcm_th3_cosq_cpu_port_info[unit] == NULL) { 2342 _bcm_th3_cosq_cleanup(unit); 2343 return BCM_E_MEMORY; 2344 } 2345 } 2346 sal_memset(_bcm_th3_cosq_cpu_port_info[unit], 0, alloc_size); 2347 2348 /* Create MMU Port Information structure */ 2349 alloc_size = sizeof(_bcm_th3_mmu_info_t); 2350 if (_bcm_th3_mmu_info[unit] == NULL) { 2351 _bcm_th3_mmu_info[unit] = 2352 sal_alloc(alloc_size, "_bcm_th3_mmu_info"); 2353 if (_bcm_th3_mmu_info[unit] == NULL) { 2354 _bcm_th3_cosq_cleanup(unit); 2355 return BCM_E_MEMORY; 2356 } 2357 } 2358 sal_memset(_bcm_th3_mmu_info[unit], 0, alloc_size); 2359 _BCM_TH3_MMU_INFO(unit)->_bcm_th3_port_info = 2360 _bcm_th3_cosq_port_info[unit]; 2361 _BCM_TH3_MMU_INFO(unit)->_bcm_th3_cpu_port_info = 2362 _bcm_th3_cosq_cpu_port_info[unit]; 2363 2364 /* Create profile for PORT_COS_MAP table */ 2365 if (_bcm_th3_cos_map_profile[unit] == NULL) { 2366 _bcm_th3_cos_map_profile[unit] = sal_alloc(sizeof(soc_profile_mem_t), 2367 "COS_MAP Profile Mem"); 2368 if (_bcm_th3_cos_map_profile[unit] == NULL) { 2369 _bcm_th3_cosq_cleanup(unit); 2370 return BCM_E_MEMORY; 2371 } 2372 soc_profile_mem_t_init(_bcm_th3_cos_map_profile[unit]); 2373 } 2374 mem = PORT_COS_MAPm; 2375 entry_words[0] = sizeof(port_cos_map_entry_t) / sizeof(uint32); 2376 2377 rv = soc_profile_mem_create(unit, &mem, entry_words, 1, 2378 _bcm_th3_cos_map_profile[unit]); 2379 if (rv != SOC_E_NONE) { 2380 _bcm_th3_cosq_cleanup(unit); 2381 return rv; 2382 } 2383 2384 /* Create profile for IFP_COS_MAP table */ 2385 if (_bcm_th3_ifp_cos_map_profile[unit] == NULL) { 2386 _bcm_th3_ifp_cos_map_profile[unit] 2387 = sal_alloc(sizeof(soc_profile_mem_t), "IFP_COS_MAP Profile Mem"); 2388 if (_bcm_th3_ifp_cos_map_profile[unit] == NULL) { 2389 _bcm_th3_cosq_cleanup(unit); 2390 return BCM_E_MEMORY; 2391 } 2392 soc_profile_mem_t_init(_bcm_th3_ifp_cos_map_profile[unit]); 2393 } 2394 mem = IFP_COS_MAPm; 2395 entry_words[0] = sizeof(ifp_cos_map_entry_t) / sizeof(uint32); 2396 2397 min_index = soc_mem_index_min(unit, IFP_COS_MAPm); 2398 max_index = soc_mem_index_max(unit, IFP_COS_MAPm) - _TH3_MMU_NUM_INT_PRI; 2399 rv = soc_profile_mem_index_create(unit, &mem, entry_words, 2400 &min_index, &max_index, NULL, 1, 2401 _bcm_th3_ifp_cos_map_profile[unit]); 2402 if (rv != SOC_E_NONE) { 2403 _bcm_th3_cosq_cleanup(unit); 2404 return rv; 2405 } 2406 2407 /* Create profile for MMU_WRED_DROP_CURVE_PROFILE_x tables */ 2408 if (_bcm_th3_wred_profile[unit] == NULL) { 2409 _bcm_th3_wred_profile[unit] = 2410 sal_alloc(sizeof(soc_profile_mem_t), "WRED Profile Mem"); 2411 if (_bcm_th3_wred_profile[unit] == NULL) { 2412 _bcm_th3_cosq_cleanup(unit); 2413 return BCM_E_MEMORY; 2414 } 2415 soc_profile_mem_t_init(_bcm_th3_wred_profile[unit]); 2416 } 2417 2418 2419 for (i = 0; i < _BCM_TH3_NUM_WRED_PROFILES; i++) { 2420 entry_words[i] = 2421 sizeof(mmu_wred_drop_curve_profile_0_entry_t) / sizeof(uint32); 2422 } 2423 2424 rv = soc_profile_mem_create(unit, wred_mems, entry_words, _BCM_TH3_NUM_WRED_PROFILES, 2425 _bcm_th3_wred_profile[unit]); 2426 if (rv != SOC_E_NONE) { 2427 _bcm_th3_cosq_cleanup(unit); 2428 return rv; 2429 } 2430 2431 if (_bcm_th3_cosq_cpu_cosq_config[unit][0] == NULL) { 2432 cpu_cosq_config_p = sal_alloc( 2433 SOC_TH3_NUM_CPU_QUEUES * sizeof(_bcm_th3_cosq_cpu_cosq_config_t), 2434 "CPU Cosq Config"); 2435 if (cpu_cosq_config_p == NULL) { 2436 _bcm_th3_cosq_cleanup(unit); 2437 return BCM_E_MEMORY; 2438 } 2439 if (NUM_CPU_COSQ(unit) > SOC_TH3_NUM_CPU_QUEUES) { 2440 /* Invalid CPU Queues */ 2441 if (cpu_cosq_config_p != NULL) { 2442 sal_free(cpu_cosq_config_p); 2443 cpu_cosq_config_p = NULL; 2444 } 2445 _bcm_th3_cosq_cleanup(unit); 2446 return BCM_E_INIT; 2447 } 2448 for (i = 0; i < NUM_CPU_COSQ(unit); i++) { 2449 _bcm_th3_cosq_cpu_cosq_config[unit][i] = cpu_cosq_config_p + i; 2450 } 2451 } 2452 2453 /* Assign default init values for RQE queue number */ 2454 rv = _bcm_th3_rqe_q_init(unit); 2455 if (rv != BCM_E_NONE) { 2456 if (cpu_cosq_config_p != NULL) { 2457 sal_free(cpu_cosq_config_p); 2458 cpu_cosq_config_p = NULL; 2459 } 2460 _bcm_th3_cosq_cleanup(unit); 2461 return rv; 2462 } 2463 2464 /* Requires ECN init to program the default Responsive/Non-responsive 2465 * settings in Hardware 2466 */ 2467 if(soc_feature(unit, soc_feature_ecn_wred)) { 2468 rv = _bcm_th3_ecn_init(unit); 2469 if (rv != BCM_E_NONE) { 2470 if (cpu_cosq_config_p != NULL) { 2471 sal_free(cpu_cosq_config_p); 2472 cpu_cosq_config_p = NULL; 2473 } 2474 _bcm_th3_cosq_cleanup(unit); 2475 return rv; 2476 } 2477 } 2478 2479 rv = _bcm_oob_init(unit); 2480 if (rv != BCM_E_NONE) { 2481 if (cpu_cosq_config_p != NULL) { 2482 sal_free(cpu_cosq_config_p); 2483 cpu_cosq_config_p = NULL; 2484 } 2485 _bcm_th3_cosq_cleanup(unit); 2486 return rv; 2487 } 2488 2489 #ifdef BCM_WARM_BOOT_SUPPORT 2490 if (SOC_WARM_BOOT(unit)) { 2491 rv = bcm_th3_cosq_reinit(unit); 2492 if (rv != BCM_E_NONE) { 2493 if (cpu_cosq_config_p != NULL) { 2494 sal_free(cpu_cosq_config_p); 2495 cpu_cosq_config_p = NULL; 2496 } 2497 _bcm_th3_cosq_cleanup(unit); 2498 } 2499 /* 2500 * COVERITY 2501 * 2502 * This checker will not be True. 2503 * cpu_cosq_config_p pointer is assigned to 2504 * _bcm_th3_cosq_cpu_cosq_config global data 2505 * structure. 2506 */ 2507 /* coverity[resource_leak] */ 2508 return rv; 2509 } else { 2510 rv = _bcm_th3_cosq_wb_alloc(unit); 2511 if (rv != BCM_E_NONE) { 2512 if (cpu_cosq_config_p != NULL) { 2513 sal_free(cpu_cosq_config_p); 2514 cpu_cosq_config_p = NULL; 2515 } 2516 _bcm_th3_cosq_cleanup(unit); 2517 return rv; 2518 } 2519 } 2520 #endif /* BCM_WARM_BOOT_SUPPORT */ 2521 2522 /* Assign default init values for CPU info */ 2523 for (i = 0; i < NUM_CPU_COSQ(unit); i++) { 2524 if (_bcm_th3_cosq_cpu_cosq_config[unit][i] == NULL) { 2525 if (cpu_cosq_config_p != NULL) { 2526 sal_free(cpu_cosq_config_p); 2527 cpu_cosq_config_p = NULL; 2528 } 2529 _bcm_th3_cosq_cleanup(unit); 2530 return BCM_E_MEMORY; 2531 } 2532 sal_memset(_bcm_th3_cosq_cpu_cosq_config[unit][i], 0, 2533 sizeof(_bcm_th3_cosq_cpu_cosq_config_t)); 2534 _bcm_th3_cosq_cpu_cosq_config[unit][i]->enable = 1; 2535 } 2536 2537 /* Add default entries for PORT_COS_MAP memory profile */ 2538 num_uc_q = _bcm_th3_get_num_ucq(unit); 2539 rv = bcm_th3_cosq_config_set(unit, num_uc_q); 2540 if (rv != BCM_E_NONE) { 2541 if (cpu_cosq_config_p != NULL) { 2542 sal_free(cpu_cosq_config_p); 2543 cpu_cosq_config_p = NULL; 2544 } 2545 _bcm_th3_cosq_cleanup(unit); 2546 return rv; 2547 } 2548 2549 if (soc_feature(unit, soc_feature_pfc_deadlock)) { 2550 rv = _bcm_th3_pfc_deadlock_init(unit); 2551 if (rv != BCM_E_NONE) { 2552 if (cpu_cosq_config_p != NULL) { 2553 sal_free(cpu_cosq_config_p); 2554 cpu_cosq_config_p = NULL; 2555 } 2556 _bcm_th3_cosq_cleanup(unit); 2557 return rv; 2558 } 2559 } 2560 2561 for (pipe = 0; pipe < NUM_PIPE(unit); pipe++) { 2562 for (itm = 0; itm < SOC_MMU_CFG_ITM_MAX; itm++) { 2563 soc_tomahawk3_pipe_map_get(unit, &pipe_map); 2564 if (pipe_map & (1 << pipe)) { 2565 mem = MMU_WRED_QUEUE_CONFIGm; 2566 rv = soc_mem_clear(unit, mem, COPYNO_ALL, 1); 2567 if (rv != SOC_E_NONE) { 2568 if (cpu_cosq_config_p != NULL) { 2569 sal_free(cpu_cosq_config_p); 2570 cpu_cosq_config_p = NULL; 2571 } 2572 _bcm_th3_cosq_cleanup(unit); 2573 return rv; 2574 } 2575 } 2576 } 2577 } 2578 2579 for (pipe = 0; pipe < NUM_PIPE(unit); pipe++) { 2580 for (itm = 0; itm < SOC_MMU_CFG_ITM_MAX; itm++) { 2581 soc_tomahawk3_pipe_map_get(unit, &pipe_map); 2582 if (pipe_map & (1 << pipe)) { 2583 mem = MMU_WRED_PORTSP_CONFIGm; 2584 rv = soc_mem_clear(unit, mem, COPYNO_ALL, 1); 2585 if (rv != SOC_E_NONE) { 2586 if (cpu_cosq_config_p != NULL) { 2587 sal_free(cpu_cosq_config_p); 2588 cpu_cosq_config_p = NULL; 2589 } 2590 _bcm_th3_cosq_cleanup(unit); 2591 return rv; 2592 } 2593 } 2594 } 2595 } 2596 2597 /* Add default entries for MMU_WRED_DROP_CURVE_PROFILE_x memory profile */ 2598 sal_memset(&entry_tcp_green, 0, sizeof(entry_tcp_green)); 2599 sal_memset(&entry_tcp_yellow,0, sizeof(entry_tcp_yellow)); 2600 sal_memset(&entry_tcp_red, 0, sizeof(entry_tcp_red)); 2601 sal_memset(&entry_nontcp_green, 0, sizeof(entry_nontcp_green)); 2602 sal_memset(&entry_nontcp_yellow, 0, sizeof(entry_nontcp_yellow)); 2603 sal_memset(&entry_nontcp_red, 0, sizeof(entry_nontcp_red)); 2604 sal_memset(&entry_ecn_green, 0, sizeof(entry_ecn_green)); 2605 sal_memset(&entry_ecn_yellow,0, sizeof(entry_ecn_yellow)); 2606 sal_memset(&entry_ecn_red, 0, sizeof(entry_ecn_red)); 2607 entries[0] = &entry_tcp_green; 2608 entries[1] = &entry_tcp_yellow; 2609 entries[2] = &entry_tcp_red; 2610 entries[3] = &entry_nontcp_green; 2611 entries[4] = &entry_nontcp_yellow; 2612 entries[5] = &entry_nontcp_red; 2613 entries[6] = &entry_ecn_green; 2614 entries[7] = &entry_ecn_yellow; 2615 entries[8] = &entry_ecn_red; 2616 2617 for (i = 0; i < _BCM_TH3_NUM_WRED_PROFILES; i++) { 2618 soc_mem_field32_set(unit, wred_mems[i], entries[i], 2619 MIN_THDf, 0x7ffff); 2620 soc_mem_field32_set(unit, wred_mems[i], entries[i], 2621 MAX_THDf, 0x7ffff); 2622 } 2623 profile_index = TH3_WRED_PROFILE_INDEX_INVALID; 2624 wred_config_mem = MMU_WRED_QUEUE_CONFIGm; 2625 wred_prof_count = soc_mem_index_count(unit, wred_config_mem); 2626 LOG_INFO(BSL_LS_BCM_COSQ, 2627 (BSL_META_U(unit, "wred_prof_count: %d\n"), 2628 wred_prof_count)); 2629 2630 2631 wred_prof_count *= (2 * NUM_PIPE(unit)); 2632 while(wred_prof_count) { 2633 if (profile_index == TH3_WRED_PROFILE_INDEX_INVALID) { 2634 rv = soc_profile_mem_add(unit, _bcm_th3_wred_profile[unit], 2635 entries, 1, &profile_index); 2636 LOG_INFO(BSL_LS_BCM_COSQ, 2637 (BSL_META_U(unit, "1 profile_index: %d\n"), 2638 profile_index)); 2639 } else { 2640 rv = soc_profile_mem_reference(unit, _bcm_th3_wred_profile[unit], 2641 profile_index, 0); 2642 LOG_INFO(BSL_LS_BCM_COSQ, 2643 (BSL_META_U(unit, "2 profile_index: %d\n"), 2644 profile_index)); 2645 } 2646 if (rv != SOC_E_NONE) { 2647 if (cpu_cosq_config_p != NULL) { 2648 sal_free(cpu_cosq_config_p); 2649 cpu_cosq_config_p = NULL; 2650 } 2651 _bcm_th3_cosq_cleanup(unit); 2652 return rv; 2653 } 2654 wred_prof_count -= 1; 2655 } 2656 2657 for (i = 0; i < _BCM_TH3_NUM_WRED_RESOLUTION_TABLE; i++) { 2658 if (i == 0) { 2659 _bcm_th3_wred_resolution_tbl[i] = 1; 2660 } else { 2661 _bcm_th3_wred_resolution_tbl[i] = 0; 2662 } 2663 } 2664 2665 _BCM_TH3_MMU_INFO(unit)->gport_tree_created = FALSE; 2666 PBMP_ALL_ITER(unit, port) { 2667 if (IS_LB_PORT(unit, port)) { 2668 continue; 2669 } 2670 rv = _bcm_th3_cosq_gport_tree_create(unit, port); 2671 if (rv != BCM_E_NONE) { 2672 if (cpu_cosq_config_p != NULL) { 2673 sal_free(cpu_cosq_config_p); 2674 cpu_cosq_config_p = NULL; 2675 } 2676 _bcm_th3_cosq_cleanup(unit); 2677 return rv; 2678 } 2679 } 2680 _BCM_TH3_MMU_INFO(unit)->gport_tree_created = TRUE; 2681 2682 rv = _bcm_th3_cosq_gport_default_config(unit); 2683 if (rv != BCM_E_NONE) { 2684 if (cpu_cosq_config_p != NULL) { 2685 sal_free(cpu_cosq_config_p); 2686 cpu_cosq_config_p = NULL; 2687 } 2688 _bcm_th3_cosq_cleanup(unit); 2689 return rv; 2690 } 2691 2692 /* BST init */ 2693 sal_memset(&bst_callbks, 0, sizeof(_bcm_bst_device_handlers_t)); 2694 bst_callbks.resolve_index = &bcm_bst_th3_index_resolve; 2695 bst_callbks.reverse_resolve_index = 2696 &_bcm_th3_cosq_bst_map_resource_to_gport_cos; 2697 rv = _bcm_bst_attach(unit, &bst_callbks); 2698 /* BST init done */ 2699 if (rv != BCM_E_NONE) { 2700 if (cpu_cosq_config_p != NULL) { 2701 sal_free(cpu_cosq_config_p); 2702 cpu_cosq_config_p = NULL; 2703 } 2704 _bcm_th3_cosq_cleanup(unit); 2705 return rv; 2706 } 2707 2708 #if defined(INCLUDE_PSTATS) 2709 if (soc_feature(unit, soc_feature_pstats)) { 2710 rv = _bcm_pstats_init(unit); 2711 if (rv != BCM_E_NONE) { 2712 if (cpu_cosq_config_p != NULL) { 2713 sal_free(cpu_cosq_config_p); 2714 cpu_cosq_config_p = NULL; 2715 } 2716 _bcm_th3_cosq_cleanup(unit); 2717 return rv; 2718 } 2719 } 2720 #endif /* INCLUDE_PSTATS */ 2721 2722 rv = soc_th3_mmu_get_shared_size(unit, 2723 _BCM_TH3_MMU_INFO(unit)->shared_limit); 2724 2725 if (rv != SOC_E_NONE) { 2726 if (cpu_cosq_config_p != NULL) { 2727 sal_free(cpu_cosq_config_p); 2728 cpu_cosq_config_p = NULL; 2729 } 2730 _bcm_th3_cosq_cleanup(unit); 2731 return rv; 2732 } 2733 2734 /* reset time_domain ref_count so that entries can be added upon 2735 * rc */ 2736 th3_time_domain_info[unit][0].ref_count = 324; 2737 th3_time_domain_info[unit][1].ref_count = 0; 2738 th3_time_domain_info[unit][2].ref_count = 0; 2739 th3_time_domain_info[unit][3].ref_count = 0; 2740 return BCM_E_NONE; 2741 } 2742 2743 /* 2744 * Function: 2745 * bcm_tomahawk3_cosq_port_profile_set 2746 * Purpose: 2747 * Set Port to Profile Mapping for Cosq profiles 2748 * Parameters: 2749 * unit - (IN) unit number 2750 * port - (IN) logical port 2751 * profile_type - (IN) Profile type 2752 * profile_id - (IN) profile id 2753 * Returns: 2754 * BCM_E_XXX 2755 */ 2756 int 2757 bcm_tomahawk3_cosq_port_profile_set(int unit, bcm_port_t port, 2758 bcm_cosq_profile_type_t profile_type, int profile_id) 2759 { 2760 if (!SOC_PORT_VALID(unit, port)) { 2761 return BCM_E_PORT; 2762 } 2763 switch (profile_type) { 2764 case bcmCosqProfilePFCAndQueueHierarchy: 2765 if ((profile_id < 0) || (profile_id >= 2766 _BCM_TH3_NUM_QSCHED_PROFILES)) { 2767 return BCM_E_PARAM; 2768 } 2769 if (!soc_tomahawk3_profile_exists(unit, profile_id)) { 2770 return BCM_E_CONFIG; 2771 } 2772 BCM_IF_ERROR_RETURN( 2773 soc_tomahawk3_sched_profile_attach(unit, port, profile_id)); 2774 BCM_IF_ERROR_RETURN( 2775 soc_tomahawk3_l1_to_l0_profile_update_per_port(unit, port, profile_id)); 2776 BCM_IF_ERROR_RETURN(_bcm_th3_cosq_gport_tree_create(unit, port)); 2777 BCM_IF_ERROR_RETURN(soc_th3_pfc_config_profile_id_set(unit, port, 2778 socTH3PFCReceiveClass, profile_id)); 2779 break; 2780 case bcmCosqProfilePGProperties: 2781 if ((profile_id < 0) || (profile_id >= 2782 _BCM_TH3_NUM_PG_PROP_PROFILES)) { 2783 return BCM_E_PARAM; 2784 } 2785 BCM_IF_ERROR_RETURN( 2786 _bcm_th3_cosq_port_pg_profile_set(unit, port, profile_id)); 2787 break; 2788 case bcmCosqProfileIntPriToPGMap: 2789 if ((profile_id < 0) || (profile_id >= 2790 _BCM_TH3_NUM_INTPRI_PG_MAP_PROFILES)) { 2791 return BCM_E_PARAM; 2792 } 2793 BCM_IF_ERROR_RETURN( 2794 _bcm_th3_cosq_port_inp_pri_to_pg_profile_set(unit, port, profile_id)); 2795 break; 2796 case bcmCosqProfileOobfcEgressQueueMap: 2797 if ((profile_id < 0) || (profile_id >= 2798 _BCM_TH3_NUM_OOB_EGRQUEUE_MAP_PROFILES)) { 2799 return BCM_E_PARAM; 2800 } 2801 BCM_IF_ERROR_RETURN( 2802 bcm_th3_oob_fx_egress_profile_id_set(unit, port, profile_id)); 2803 break; 2804 default: 2805 return SOC_E_PARAM; 2806 break; 2807 } 2808 2809 return SOC_E_NONE; 2810 } 2811 2812 2813 /* 2814 * Function: 2815 * bcm_tomahawk3_cosq_port_profile_get 2816 * Purpose: 2817 * Get Port to Profile Mapping for Cosq profiles 2818 * Parameters: 2819 * unit - (IN) unit number 2820 * port - (IN) logical port 2821 * profile_type - (IN) Profile type 2822 * profile_id - (OUT) profile id 2823 * Returns: 2824 * BCM_E_XXX 2825 */ 2826 int 2827 bcm_tomahawk3_cosq_port_profile_get(int unit, bcm_port_t port, 2828 bcm_cosq_profile_type_t profile_type, int *profile_id) 2829 { 2830 if (!SOC_PORT_VALID(unit, port)) { 2831 return BCM_E_PORT; 2832 } 2833 if (profile_id == NULL) { 2834 return BCM_E_PARAM; 2835 } 2836 switch (profile_type) { 2837 case bcmCosqProfilePFCAndQueueHierarchy: 2838 BCM_IF_ERROR_RETURN( 2839 soc_tomahawk3_sched_profile_get(unit, port, profile_id)); 2840 break; 2841 case bcmCosqProfilePGProperties: 2842 BCM_IF_ERROR_RETURN( 2843 _bcm_th3_cosq_port_pg_profile_get(unit, port, profile_id)); 2844 break; 2845 case bcmCosqProfileIntPriToPGMap: 2846 BCM_IF_ERROR_RETURN( 2847 _bcm_th3_cosq_port_inp_pri_to_pg_profile_get(unit, port, profile_id)); 2848 break; 2849 case bcmCosqProfileOobfcEgressQueueMap: 2850 BCM_IF_ERROR_RETURN( 2851 bcm_th3_oob_fx_egress_profile_id_get(unit, port, profile_id)); 2852 break; 2853 default: 2854 return SOC_E_PARAM; 2855 break; 2856 } 2857 2858 return SOC_E_NONE; 2859 } 2860 2861 /* 2862 * Function: 2863 * bcm_tomahawk3_cosq_profile_property_dynamic_get 2864 * Purpose: 2865 * Query if a profile can be modified dynamically 2866 * Parameters: 2867 * unit - (IN) unit number 2868 * profile_type - (IN) Profile type 2869 * dynamic - (OUT) Dynamic changeable type 2870 * Returns: 2871 * BCM_E_XXX 2872 */ 2873 int 2874 bcm_tomahawk3_cosq_profile_property_dynamic_get(int unit, 2875 bcm_cosq_profile_type_t profile_type, bcm_cosq_dynamic_setting_type_t 2876 *dynamic) 2877 { 2878 if (dynamic == NULL) { 2879 return BCM_E_PARAM; 2880 } 2881 switch (profile_type) { 2882 case bcmCosqProfilePFCAndQueueHierarchy: 2883 *dynamic = bcmCosqDynamicTypeConditional; 2884 break; 2885 case bcmCosqProfilePGProperties: 2886 *dynamic = bcmCosqDynamicTypeFixed; 2887 break; 2888 case bcmCosqProfileIntPriToPGMap: 2889 *dynamic = bcmCosqDynamicTypeFlexible; 2890 break; 2891 case bcmCosqProfileOobfcEgressQueueMap: 2892 *dynamic = bcmCosqDynamicTypeConditional; 2893 break; 2894 default: 2895 return SOC_E_PARAM; 2896 break; 2897 } 2898 2899 return SOC_E_NONE; 2900 } 2901 2902 /* 2903 * Function: 2904 * bcm_tomahawk3_cosq_profile_info_inuse_get 2905 * Purpose: 2906 * Query if a profile id of a profile is in use 2907 * Parameters: 2908 * unit - (IN) unit number 2909 * profile_type - (IN) Profile type 2910 * profile_id - (IN) Profile id 2911 * in_use - (OUT) If a profile is in use 2912 * Returns: 2913 * BCM_E_XXX 2914 */ 2915 int 2916 bcm_tomahawk3_cosq_profile_info_inuse_get(int unit, 2917 bcm_cosq_profile_type_t profile_type, int profile_id, int *in_use) 2918 { 2919 int port, ret_profile = -1; 2920 if (in_use == NULL) { 2921 return BCM_E_PARAM; 2922 } 2923 switch (profile_type) { 2924 case bcmCosqProfilePFCAndQueueHierarchy: 2925 if ((profile_id < 0) || (profile_id >= 2926 _BCM_TH3_NUM_QSCHED_PROFILES)) { 2927 return BCM_E_PARAM; 2928 } 2929 break; 2930 case bcmCosqProfilePGProperties: 2931 if ((profile_id < 0) || (profile_id >= 2932 _BCM_TH3_NUM_PG_PROP_PROFILES)) { 2933 return BCM_E_PARAM; 2934 } 2935 break; 2936 case bcmCosqProfileIntPriToPGMap: 2937 if ((profile_id < 0) || (profile_id >= 2938 _BCM_TH3_NUM_INTPRI_PG_MAP_PROFILES)) { 2939 return BCM_E_PARAM; 2940 } 2941 break; 2942 case bcmCosqProfileOobfcEgressQueueMap: 2943 if ((profile_id < 0) || (profile_id >= 2944 _BCM_TH3_NUM_OOB_EGRQUEUE_MAP_PROFILES)) { 2945 return BCM_E_PARAM; 2946 } 2947 break; 2948 default: 2949 return BCM_E_PARAM; 2950 break; 2951 } 2952 PBMP_ALL_ITER(unit, port) { 2953 if (profile_type == bcmCosqProfilePFCAndQueueHierarchy) { 2954 if (IS_CPU_PORT(unit, port)) { 2955 continue; 2956 } 2957 } 2958 BCM_IF_ERROR_RETURN( 2959 bcm_tomahawk3_cosq_port_profile_get(unit, port, profile_type, 2960 &ret_profile)); 2961 if (ret_profile == profile_id) { 2962 *in_use = 1; 2963 return BCM_E_NONE; 2964 } 2965 } 2966 *in_use = 0; 2967 2968 return BCM_E_NONE; 2969 } 2970 2971 /* 2972 * Function: 2973 * bcm_tomahawk3_cosq_profile_info_portlist_get 2974 * Purpose: 2975 * Query the list of ports using a specific profile 2976 * Parameters: 2977 * unit - (IN) unit number 2978 * profile_type - (IN) Profile type 2979 * profile_id - (IN) Profile id 2980 * port_count - (OUT) Number of ports using this profile 2981 * max_port_count - (OUT) Max Number of ports that can use this profile 2982 * port_list - (OUT) List of ports using this profile 2983 * Returns: 2984 * BCM_E_XXX 2985 */ 2986 int 2987 bcm_tomahawk3_cosq_profile_info_portlist_get(int unit, 2988 bcm_cosq_profile_type_t profile_type, int profile_id, int max_port_count, 2989 bcm_port_t *port_list, int *port_count) 2990 { 2991 int port, ret_profile = -1; 2992 if (port_count == NULL || port_list == NULL) { 2993 return BCM_E_PARAM; 2994 } 2995 if (max_port_count <= 0 || max_port_count > SOC_TH3_MAX_NUM_PORTS) { 2996 return BCM_E_PARAM; 2997 } 2998 switch (profile_type) { 2999 case bcmCosqProfilePFCAndQueueHierarchy: 3000 if ((profile_id < 0) || (profile_id >= 3001 _BCM_TH3_NUM_QSCHED_PROFILES)) { 3002 return BCM_E_PARAM; 3003 } 3004 break; 3005 case bcmCosqProfilePGProperties: 3006 if ((profile_id < 0) || (profile_id >= 3007 _BCM_TH3_NUM_PG_PROP_PROFILES)) { 3008 return BCM_E_PARAM; 3009 } 3010 break; 3011 case bcmCosqProfileIntPriToPGMap: 3012 if ((profile_id < 0) || (profile_id >= 3013 _BCM_TH3_NUM_INTPRI_PG_MAP_PROFILES)) { 3014 return BCM_E_PARAM; 3015 } 3016 break; 3017 case bcmCosqProfileOobfcEgressQueueMap: 3018 if ((profile_id < 0) || (profile_id >= 3019 _BCM_TH3_NUM_OOB_EGRQUEUE_MAP_PROFILES)) { 3020 return BCM_E_PARAM; 3021 } 3022 break; 3023 default: 3024 return BCM_E_PARAM; 3025 break; 3026 } 3027 *port_count = 0; 3028 PBMP_ALL_ITER(unit, port) { 3029 if (profile_type == bcmCosqProfilePFCAndQueueHierarchy) { 3030 if (IS_CPU_PORT(unit, port)) { 3031 continue; 3032 } 3033 } 3034 BCM_IF_ERROR_RETURN( 3035 bcm_tomahawk3_cosq_port_profile_get(unit, port, profile_type, 3036 &ret_profile)); 3037 if (ret_profile == profile_id) { 3038 port_list[(*port_count)++] = port; 3039 if((*port_count) == max_port_count) { 3040 break; 3041 } 3042 } 3043 } 3044 return BCM_E_NONE; 3045 } 3046 3047 /* 3048 * This function does two things: 3049 * 1. Tests whether the corresponding COS_BMP bit is set or not. 3050 * 2. Tests whether the queue corresponding to given cos is 3051 * mapped to correct L0 or not. 3052 * 3053 * L0.0 is associated with CMC0 CH1(Rx) (pci) 3054 * L0.1 is associated with CMC0 CH2(Rx) (pci) 3055 * L0.2 is associated with CMC0 CH3(Rx) (pci) 3056 * L0.3 is associated with CMC0 CH4(Rx) (pci) 3057 * L0.4 is associated with CMC0 CH5(Rx) (pci) 3058 * L0.5 is associated with CMC0 CH6(Rx) (pci) 3059 * L0.6 is associated with CMC0 CH7(Rx) (pci) 3060 * L0.7 is associated with CMC1 CHx(Rx) (uc0) 3061 * L0.8 is associated with CMC1 CHx(Rx) (uC1) 3062 * L0.11 is reserved 3063 */ 3064 int 3065 bcm_th3_rx_queue_channel_set_test(int unit, bcm_cos_queue_t queue_id, 3066 bcm_rx_chan_t chan_id) 3067 { 3068 #if defined(BCM_CMICX_SUPPORT) 3069 if (soc_feature(unit, soc_feature_cmicx)) { 3070 int pci_cmc = SOC_PCI_CMC(unit); 3071 uint32 reg_val; 3072 uint32 bit; 3073 uint32 max_rx_channels = 0; 3074 _bcm_th3_cosq_cpu_port_info_t *cpu_port_info = NULL; 3075 bcm_gport_t cpu_l0_gport = -1; 3076 bcm_gport_t parent_gport = -1; 3077 3078 soc_dma_max_rx_channels_get(unit, &max_rx_channels); 3079 3080 if ((chan_id <= 0) || (chan_id >= max_rx_channels)) { 3081 return BCM_E_PARAM; 3082 } 3083 3084 if (_bcm_th3_cosq_cpu_port_info[unit] == NULL) { 3085 return BCM_E_INIT; 3086 } 3087 3088 cpu_port_info = _bcm_th3_cosq_cpu_port_info[unit]; 3089 3090 if ((chan_id > 0) && (chan_id < 8 )) { 3091 cpu_l0_gport = cpu_port_info->sched[chan_id - 1].gport; 3092 } 3093 3094 if (queue_id < 0) { /* All COS Queues */ 3095 for (queue_id = 0; queue_id < NUM_CPU_COSQ(unit); queue_id++) { 3096 soc_dma_cos_ctrl_queue_get(unit, pci_cmc, chan_id, queue_id, 3097 ®_val); 3098 3099 bit = 1 << (queue_id % 32); 3100 if (reg_val & bit) { 3101 /* find the parent gport of this queue if parent gport is 3102 * not equal to l0 gport for this channel return error */ 3103 parent_gport = cpu_port_info->mcast[queue_id].parent_gport; 3104 if (parent_gport != cpu_l0_gport) { 3105 return BCM_E_PARAM; 3106 } 3107 } 3108 } 3109 } else { 3110 soc_dma_cos_ctrl_queue_get(unit, pci_cmc, chan_id, queue_id, 3111 ®_val); 3112 bit = 1 << (queue_id % 32); 3113 if (reg_val & bit) { 3114 /* find the parent gport of this queue if parent gport is not 3115 * equal to l0 gport for this channel return error */ 3116 parent_gport = cpu_port_info->mcast[queue_id].parent_gport; 3117 if (parent_gport != cpu_l0_gport) { 3118 return BCM_E_PARAM; 3119 } 3120 } else { 3121 return BCM_E_PARAM; 3122 } 3123 } 3124 } 3125 #endif /* BCM_CMICX_SUPPORT */ 3126 3127 return BCM_E_NONE; 3128 } 3129 3130 /* 3131 * Function: 3132 * _bcm_th3_cosq_localport_resolve 3133 * Purpose: 3134 * Resolve GPORT if it is a local port 3135 * Parameters: 3136 * unit - (IN) unit number 3137 * gport - (IN) GPORT identifier 3138 * local_port - (OUT) local port number 3139 * Returns: 3140 * BCM_E_XXX 3141 */ 3142 int 3143 _bcm_th3_cosq_localport_resolve(int unit, bcm_gport_t gport, 3144 bcm_port_t *local_port) 3145 { 3146 bcm_module_t module; 3147 bcm_port_t port; 3148 bcm_trunk_t trunk; 3149 int id, result, rv; 3150 3151 if (!BCM_GPORT_IS_SET(gport)) { 3152 if (!SOC_PORT_VALID(unit, gport)) { 3153 return BCM_E_PORT; 3154 } 3155 *local_port = gport; 3156 return BCM_E_NONE; 3157 } 3158 3159 rv = _bcm_esw_gport_resolve(unit, gport, &module, &port, &trunk, &id); 3160 if (rv == BCM_E_PORT) { 3161 /* returning E_PARAM when invalid gport is given as param */ 3162 return BCM_E_PARAM; 3163 } else if (BCM_FAILURE(rv)) { 3164 return rv; 3165 } 3166 3167 BCM_IF_ERROR_RETURN(_bcm_esw_modid_is_local(unit, module, &result)); 3168 if (result == FALSE) { 3169 return BCM_E_PARAM; 3170 } 3171 3172 *local_port = port; 3173 3174 return BCM_E_NONE; 3175 } 3176 3177 int 3178 _bcm_th3_cosq_egress_sp_get(int unit, bcm_gport_t gport, bcm_cos_queue_t cosq, 3179 int *p_pool_start, int *p_pool_end) 3180 { 3181 int local_port; 3182 int pool; 3183 3184 if (cosq == BCM_COS_INVALID) { 3185 if (p_pool_start && p_pool_end) { 3186 *p_pool_start = 0; 3187 *p_pool_end = 3; 3188 return BCM_E_NONE; 3189 } else { 3190 return BCM_E_PARAM; 3191 } 3192 } 3193 3194 BCM_IF_ERROR_RETURN 3195 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 3196 _BCM_TH3_COSQ_INDEX_STYLE_EGR_POOL, 3197 &local_port, &pool, NULL)); 3198 3199 if (p_pool_start) { 3200 *p_pool_start = pool; 3201 } 3202 if (p_pool_end) { 3203 *p_pool_end = pool; 3204 } 3205 return BCM_E_NONE; 3206 } 3207 3208 /* 3209 * Function: 3210 * _bcm_th3_cosq_index_resolve 3211 * Purpose: 3212 * Find hardware index for the given port/cosq 3213 * Parameters: 3214 * unit - (IN) unit number 3215 * port - (IN) port number or GPORT identifier 3216 * cosq - (IN) COS queue number 3217 * style - (IN) index style (_BCM_KA_COSQ_INDEX_STYLE_XXX) 3218 * local_port - (OUT) local port number 3219 * index - (OUT) result index 3220 * count - (OUT) number of index 3221 * Returns: 3222 * BCM_E_XXX 3223 */ 3224 int 3225 _bcm_th3_cosq_index_resolve(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 3226 _bcm_th3_cosq_index_style_t style, 3227 bcm_port_t *local_port, int *index, int *count) 3228 { 3229 bcm_port_t resolved_port; 3230 soc_info_t *si; 3231 int resolved_index = -1; 3232 int id, startq, numq = 0; 3233 int num_uc_q, num_mc_q; 3234 int pipe; 3235 int uc_base = 0, mc_base = 0, cpu_mc_base = 0; /* Q base number */ 3236 int chip_mmu_port; /* chip_port_num*/ 3237 _bcm_th3_cosq_node_t *node; 3238 uint32 entry[SOC_MAX_MEM_WORDS]; 3239 soc_mem_t mem; 3240 3241 si = &SOC_INFO(unit); 3242 3243 if (cosq < -1) { 3244 return BCM_E_PARAM; 3245 } else if (cosq == -1) { 3246 startq = 0; 3247 numq = _TH3_NUM_COS(unit); 3248 } else { 3249 startq = cosq; 3250 numq = 1; 3251 } 3252 3253 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port) || 3254 BCM_GPORT_IS_MCAST_QUEUE_GROUP(port) || 3255 BCM_GPORT_IS_SCHEDULER(port)) { 3256 BCM_IF_ERROR_RETURN 3257 (_bcm_th3_cosq_node_get(unit, port, NULL, &resolved_port, &id, 3258 &node)); 3259 if (resolved_port < 0) { 3260 return BCM_E_PORT; 3261 } 3262 } else { 3263 BCM_IF_ERROR_RETURN 3264 (_bcm_th3_cosq_localport_resolve(unit, port, &resolved_port)); 3265 if (resolved_port < 0) { 3266 return BCM_E_PORT; 3267 } 3268 node = NULL; 3269 numq = (IS_CPU_PORT(unit, resolved_port)) ? NUM_CPU_COSQ(unit) : _BCM_TH3_COS_MAX; 3270 } 3271 num_uc_q = _bcm_th3_get_num_ucq(unit); 3272 num_mc_q = _bcm_th3_get_num_mcq(unit); 3273 mc_base = si->port_cosq_base[resolved_port]; 3274 uc_base = si->port_uc_cosq_base[resolved_port]; 3275 3276 SOC_IF_ERROR_RETURN(soc_port_pipe_get(unit, resolved_port, &pipe)); 3277 3278 switch (style) { 3279 case _BCM_TH3_COSQ_INDEX_STYLE_WRED_DEVICE: 3280 if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(port)) { 3281 return BCM_E_PARAM; 3282 } 3283 if ((port == -1) || (cosq == -1)) { 3284 numq = _TH3_MMU_NUM_POOL; /* 4 Global Service Pools */ 3285 resolved_index = 0; 3286 } else { 3287 BCM_IF_ERROR_RETURN 3288 (_bcm_th3_cosq_egress_sp_get(unit, port, cosq, 3289 &resolved_index, 3290 NULL)); 3291 numq = 1; 3292 resolved_index += 0; 3293 } 3294 break; 3295 case _BCM_TH3_COSQ_INDEX_STYLE_WRED_PORT: 3296 if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(port)) { 3297 return BCM_E_PARAM; 3298 } 3299 resolved_index = 0; 3300 if (cosq != -1) { 3301 BCM_IF_ERROR_RETURN 3302 (_bcm_th3_cosq_egress_sp_get(unit, port, cosq, 3303 &resolved_index, 3304 NULL)); 3305 } 3306 chip_mmu_port = SOC_TH3_MMU_CHIP_PORT(unit, resolved_port); 3307 resolved_index += (chip_mmu_port * 4); /* resolved_index is chip_port_num, spid.*/ 3308 numq = (cosq == -1) ? 4: 1; 3309 break; 3310 case _BCM_TH3_COSQ_INDEX_STYLE_WRED_QUEUE: 3311 if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(port)) { 3312 return BCM_E_PARAM; 3313 } 3314 /* resolved_index = local_mmu_port * _BCM_TH3_MAX_QUEUE_PER_PORT; */ 3315 resolved_index = uc_base; 3316 if (cosq != -1) { 3317 if (cosq >= _bcm_th3_get_num_ucq(unit)) { /* WRED is only for UCQ*/ 3318 return BCM_E_PARAM; 3319 } 3320 resolved_index += cosq; 3321 } 3322 numq = (cosq == -1) ? _bcm_th3_get_num_ucq(unit): 1; 3323 break; 3324 case _BCM_TH3_COSQ_INDEX_STYLE_EGR_POOL: 3325 if ((node != NULL) && (!BCM_GPORT_IS_MODPORT(port))) { 3326 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port)) { 3327 /* regular unicast queue */ 3328 resolved_index = (uc_base + (node->hw_index % 3329 num_uc_q)); 3330 mem = MMU_THDO_Q_TO_QGRP_MAPD0m; 3331 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(port)) { 3332 if (IS_CPU_PORT(unit, resolved_port)) { 3333 cpu_mc_base = si->port_cosq_base[CMIC_PORT(unit)]; 3334 resolved_index = cpu_mc_base + 3335 ((node->hw_index - cpu_mc_base) % 3336 _BCM_TH3_NUM_CPU_MCAST_QUEUE); 3337 } else { 3338 resolved_index = (mc_base + (node->hw_index % 3339 num_mc_q)); 3340 } 3341 mem = MMU_THDO_Q_TO_QGRP_MAPD0m; 3342 } else { /* scheduler */ 3343 return BCM_E_PARAM; 3344 } 3345 } else { /* node == NULL */ 3346 numq = si->port_num_cosq[resolved_port] + 3347 si->port_num_uc_cosq[resolved_port]; 3348 if (startq >= numq) { 3349 return BCM_E_PARAM; 3350 } 3351 resolved_index = (IS_CPU_PORT(unit, resolved_port) ? mc_base : uc_base) + startq; 3352 mem = MMU_THDO_Q_TO_QGRP_MAPD0m; 3353 } 3354 SOC_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ALL, resolved_index, 3355 entry)); 3356 resolved_index = soc_mem_field32_get(unit, mem, entry, SPIDf); 3357 break; 3358 case _BCM_TH3_COSQ_INDEX_STYLE_COS: 3359 if (node) { 3360 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port)) { 3361 resolved_index = node->hw_index % num_uc_q; 3362 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(port)) { 3363 if (IS_CPU_PORT(unit, resolved_port)) { 3364 cpu_mc_base = si->port_cosq_base[CMIC_PORT(unit)]; 3365 resolved_index = (node->hw_index - cpu_mc_base) % 3366 NUM_CPU_COSQ(unit); 3367 } else { 3368 resolved_index = node->hw_index % num_mc_q; 3369 } 3370 } else { 3371 resolved_index = node->hw_index % 3372 _BCM_TH3_NUM_SCHEDULER_PER_PORT; 3373 } 3374 } else { 3375 resolved_index = startq; 3376 } 3377 break; 3378 case _BCM_TH3_COSQ_INDEX_STYLE_UCAST_QUEUE: 3379 /* Return hw_index for given unicast queue gport */ 3380 if (node) { 3381 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port)) { 3382 resolved_index = (uc_base + (node->hw_index % num_uc_q)); 3383 } else { 3384 return BCM_E_PARAM; 3385 } 3386 } else { 3387 if (IS_CPU_PORT(unit, resolved_port)) { 3388 return BCM_E_PARAM; 3389 } 3390 if (startq >= num_uc_q) { 3391 return BCM_E_PARAM; 3392 } 3393 resolved_index = uc_base + startq; 3394 } 3395 break; 3396 case _BCM_TH3_COSQ_INDEX_STYLE_MCAST_QUEUE: 3397 /* Return hw_index for given multicast queue gport */ 3398 if (node) { 3399 if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(port)) { 3400 if (IS_CPU_PORT(unit, resolved_port)) { 3401 cpu_mc_base = si->port_cosq_base[CMIC_PORT(unit)]; 3402 resolved_index = cpu_mc_base + 3403 ((node->hw_index - cpu_mc_base) % 3404 _BCM_TH3_NUM_CPU_MCAST_QUEUE); 3405 } else { 3406 resolved_index = (mc_base + (node->hw_index % num_mc_q)); 3407 } 3408 } else { 3409 return BCM_E_PARAM; 3410 } 3411 } else { 3412 if (IS_CPU_PORT(unit, resolved_port)) { 3413 if (startq >= numq) { 3414 return BCM_E_PARAM; 3415 } 3416 resolved_index = mc_base + startq; 3417 } else { 3418 if ((startq < num_uc_q) || (startq >= numq)) { 3419 return BCM_E_PARAM; 3420 } 3421 resolved_index = mc_base + (startq - num_uc_q); 3422 } 3423 } 3424 break; 3425 default: 3426 return BCM_E_PARAM; 3427 } 3428 3429 if (index) { 3430 *index = resolved_index; 3431 } 3432 if (local_port) { 3433 *local_port = resolved_port; 3434 } 3435 if (count) { 3436 *count = (cosq == -1) ? numq : 1; 3437 } 3438 3439 return BCM_E_NONE; 3440 } 3441 3442 3443 /* 3444 * Function: 3445 * _bcm_th3_cosq_mapping_set 3446 * Purpose: 3447 * Set COS queue for the specified priority of an ingress port 3448 * Parameters: 3449 * unit - (IN) unit number 3450 * ing_port - (IN) ingress port 3451 * gport - (IN) queue group GPORT identifier 3452 * priority - (IN) priority value to map 3453 * flags - (IN) BCM_COSQ_GPORT_XXX_QUEUE_GROUP 3454 * gport - (IN) queue group GPORT identifier 3455 * cosq - (IN) COS queue number 3456 * Returns: 3457 * BCM_E_XXX 3458 */ 3459 int 3460 _bcm_th3_cosq_mapping_set(int unit, bcm_port_t ing_port, bcm_cos_t priority, 3461 uint32 flags, bcm_gport_t gport, bcm_cos_queue_t cosq1, 3462 bcm_cos_queue_t cosq2) 3463 { 3464 bcm_port_t local_port, out_port; 3465 bcm_cos_queue_t hw_cosq[3]; 3466 int rv, idx; 3467 soc_field_t field[3] = {INVALIDf, INVALIDf, INVALIDf}; /* [0]:UC, [1]:MC cos */ 3468 void *entries[1]; 3469 cos_map_sel_entry_t cos_map_sel_entry; 3470 port_cos_map_entry_t cos_map_entries[_TH3_MMU_NUM_INT_PRI]; 3471 uint32 old_index, new_index; 3472 int num_ucq, num_mcq; 3473 3474 num_ucq = _bcm_th3_get_num_ucq(unit); 3475 num_mcq = _bcm_th3_get_num_mcq(unit); 3476 3477 BCM_IF_ERROR_RETURN 3478 (_bcm_th3_cosq_localport_resolve(unit, ing_port, &local_port)); 3479 3480 if (gport != -1) { 3481 BCM_IF_ERROR_RETURN(_bcm_th3_cosq_localport_resolve(unit, gport, 3482 &out_port)); 3483 } 3484 3485 switch (flags) { 3486 case BCM_COSQ_GPORT_UCAST_QUEUE_GROUP: 3487 if (gport == -1) { 3488 hw_cosq[0] = cosq1; 3489 } else { 3490 if (!BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 3491 return BCM_E_PARAM; 3492 } 3493 BCM_IF_ERROR_RETURN 3494 (_bcm_th3_cosq_index_resolve 3495 (unit, gport, cosq1, _BCM_TH3_COSQ_INDEX_STYLE_COS, 3496 NULL, &hw_cosq[0], NULL)); 3497 } 3498 hw_cosq[0] %= num_ucq; 3499 field[0] = UC_COS1f; 3500 break; 3501 case BCM_COSQ_GPORT_ELEPHANT_UCAST_QUEUE_GROUP: 3502 if (gport == -1) { 3503 hw_cosq[0] = cosq1; 3504 } else { 3505 if (!BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 3506 return BCM_E_PARAM; 3507 } 3508 BCM_IF_ERROR_RETURN 3509 (_bcm_th3_cosq_index_resolve 3510 (unit, gport, cosq1, _BCM_TH3_COSQ_INDEX_STYLE_COS, 3511 NULL, &hw_cosq[0], NULL)); 3512 } 3513 hw_cosq[0] %= num_ucq; 3514 field[0] = UC_COS2f; 3515 break; 3516 case BCM_COSQ_GPORT_MCAST_QUEUE_GROUP: 3517 if (gport == -1) { 3518 hw_cosq[0] = cosq1; 3519 } else { 3520 if (!BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 3521 return BCM_E_PARAM; 3522 } 3523 BCM_IF_ERROR_RETURN 3524 (_bcm_th3_cosq_index_resolve 3525 (unit, gport, cosq1, _BCM_TH3_COSQ_INDEX_STYLE_COS, 3526 NULL, &hw_cosq[0], NULL)); 3527 } 3528 hw_cosq[0] %= num_mcq; 3529 field[0] = MC_COS1f; 3530 break; 3531 case (BCM_COSQ_GPORT_UCAST_QUEUE_GROUP | 3532 BCM_COSQ_GPORT_MCAST_QUEUE_GROUP): 3533 if (gport == -1) { 3534 hw_cosq[0] = cosq1; 3535 hw_cosq[1] = cosq2; 3536 } else { 3537 return BCM_E_PARAM; 3538 } 3539 /* 3540 hw_cosq[0] %= _BCM_TH3_NUM_SCHEDULER_PER_PORT; 3541 hw_cosq[1] %= _BCM_TH3_NUM_SCHEDULER_PER_PORT; 3542 hw_cosq[2] %= _BCM_TH3_NUM_SCHEDULER_PER_PORT; 3543 */ 3544 hw_cosq[0] = MIN(hw_cosq[0], num_ucq - 1); 3545 hw_cosq[1] = MIN(hw_cosq[1], num_mcq ? num_mcq - 1 : 0); 3546 field[0] = UC_COS1f; 3547 field[1] = MC_COS1f; 3548 break; 3549 default: 3550 return BCM_E_PARAM; 3551 } 3552 3553 entries[0] = &cos_map_entries; 3554 3555 BCM_IF_ERROR_RETURN 3556 (READ_COS_MAP_SELm(unit, MEM_BLOCK_ANY, local_port, 3557 &cos_map_sel_entry)); 3558 old_index = soc_mem_field32_get(unit, COS_MAP_SELm, &cos_map_sel_entry, 3559 SELECTf); 3560 old_index *= _TH3_MMU_NUM_INT_PRI; 3561 3562 BCM_IF_ERROR_RETURN 3563 (soc_profile_mem_get(unit, _bcm_th3_cos_map_profile[unit], 3564 old_index, _TH3_MMU_NUM_INT_PRI, entries)); 3565 3566 for (idx = 0; idx < 3; idx++) { 3567 if (field[idx] != INVALIDf) { 3568 soc_mem_field32_set(unit, PORT_COS_MAPm, 3569 &cos_map_entries[priority], 3570 field[idx], hw_cosq[idx]); 3571 } 3572 } 3573 3574 soc_mem_lock(unit, PORT_COS_MAPm); 3575 3576 rv = soc_profile_mem_delete(unit, _bcm_th3_cos_map_profile[unit], 3577 old_index); 3578 if (BCM_FAILURE(rv)) { 3579 soc_mem_unlock(unit, PORT_COS_MAPm); 3580 return rv; 3581 } 3582 3583 rv = soc_profile_mem_add(unit, _bcm_th3_cos_map_profile[unit], entries, 3584 _TH3_MMU_NUM_INT_PRI, &new_index); 3585 3586 soc_mem_unlock(unit, PORT_COS_MAPm); 3587 3588 if (BCM_FAILURE(rv)) { 3589 return rv; 3590 } 3591 soc_mem_field32_set(unit, COS_MAP_SELm, &cos_map_sel_entry, SELECTf, 3592 new_index / _TH3_MMU_NUM_INT_PRI); 3593 BCM_IF_ERROR_RETURN 3594 (WRITE_COS_MAP_SELm(unit, MEM_BLOCK_ANY, local_port, 3595 &cos_map_sel_entry)); 3596 #ifndef BCM_COSQ_HIGIG_MAP_DISABLE 3597 if (IS_CPU_PORT(unit, local_port)) { 3598 BCM_IF_ERROR_RETURN 3599 (soc_mem_field32_modify(unit, COS_MAP_SELm, 3600 SOC_INFO(unit).cpu_hg_index, SELECTf, 3601 new_index / _TH3_MMU_NUM_INT_PRI)); 3602 } 3603 #endif /* BCM_COSQ_HIGIG_MAP_DISABLE */ 3604 3605 return BCM_E_NONE; 3606 } 3607 3608 /* 3609 * Function: 3610 * bcm_th3_cosq_mapping_set 3611 * Purpose: 3612 * Set which cosq a given priority should fall into 3613 * Parameters: 3614 * unit - (IN) unit number 3615 * gport - (IN) queue group GPORT identifier 3616 * priority - (IN) priority value to map 3617 * cosq - (IN) COS queue to map to 3618 * Returns: 3619 * BCM_E_XXX 3620 */ 3621 3622 int 3623 bcm_th3_cosq_mapping_set(int unit, bcm_port_t port, bcm_cos_t priority, 3624 bcm_cos_queue_t cosq) 3625 { 3626 bcm_pbmp_t pbmp; 3627 bcm_port_t local_port; 3628 3629 BCM_PBMP_CLEAR(pbmp); 3630 3631 if ((priority < 0) || (priority >= _TH3_MMU_NUM_INT_PRI)) { 3632 return BCM_E_PARAM; 3633 } 3634 3635 if (cosq < 0) { 3636 return BCM_E_PARAM; 3637 } 3638 3639 if (port == -1) { 3640 /* port value of -1 will cause the cosq mapping set for 3641 all types of local ports except Loopback ports. 3642 So we do the sanity check of cos value with Default Number 3643 of COS */ 3644 if (cosq >= _TH3_NUM_COS(unit)) { 3645 return BCM_E_PARAM; 3646 } 3647 BCM_PBMP_ASSIGN(pbmp, PBMP_ALL(unit)); 3648 } else { 3649 if (BCM_GPORT_IS_SET(port)) { 3650 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port) || 3651 BCM_GPORT_IS_MCAST_QUEUE_GROUP(port) || 3652 BCM_GPORT_IS_SCHEDULER(port)) { 3653 return BCM_E_PARAM; 3654 } else if (BCM_GPORT_IS_LOCAL(port)) { 3655 local_port = BCM_GPORT_LOCAL_GET(port); 3656 } else if (BCM_GPORT_IS_MODPORT(port)) { 3657 BCM_IF_ERROR_RETURN( 3658 bcm_esw_port_local_get(unit, port, &local_port)); 3659 } else { 3660 return BCM_E_PARAM; 3661 } 3662 } else { 3663 local_port = port; 3664 } 3665 3666 if (!SOC_PORT_VALID(unit, local_port)) { 3667 return BCM_E_PORT; 3668 } 3669 3670 BCM_PBMP_PORT_ADD(pbmp, local_port); 3671 if (cosq >= _TH3_PORT_NUM_COS(unit, local_port)) { 3672 return BCM_E_PARAM; 3673 } 3674 } 3675 3676 PBMP_ITER(pbmp, local_port) { 3677 if (IS_LB_PORT(unit, local_port)) { 3678 continue; 3679 } 3680 3681 /* If no ETS/gport, map the int prio symmetrically for ucast and 3682 * mcast */ 3683 BCM_IF_ERROR_RETURN 3684 (_bcm_th3_cosq_mapping_set(unit, local_port, 3685 priority, 3686 BCM_COSQ_GPORT_UCAST_QUEUE_GROUP | 3687 BCM_COSQ_GPORT_MCAST_QUEUE_GROUP, 3688 -1, cosq, cosq)); 3689 } 3690 3691 return BCM_E_NONE; 3692 } 3693 3694 3695 /* 3696 * Function: 3697 * _bcm_th3_cosq_mapping_get 3698 * Purpose: 3699 * Determine which COS queue a given priority currently maps to. 3700 * Parameters: 3701 * unit - (IN) unit number 3702 * gport - (IN) queue group GPORT identifier 3703 * priority - (IN) priority value to map 3704 * cosq - (OUT) COS queue to map to 3705 * Returns: 3706 * BCM_E_XXX 3707 */ 3708 int 3709 _bcm_th3_cosq_mapping_get(int unit, bcm_port_t ing_port, bcm_cos_t priority, 3710 uint32 flags, bcm_gport_t *gport, 3711 bcm_cos_queue_t *cosq) 3712 { 3713 bcm_port_t local_port; 3714 cos_map_sel_entry_t cos_map_sel_entry; 3715 _bcm_th3_cosq_port_info_t *port_info = NULL; 3716 _bcm_th3_cosq_cpu_port_info_t *cpu_port_info = NULL; 3717 _bcm_th3_cosq_node_t *node; 3718 int ii, index, cosq_base = 0; 3719 void *entry_p; 3720 bcm_cos_queue_t hw_cosq = BCM_COS_INVALID, node_cosq = BCM_COS_INVALID; 3721 int numq = -1; 3722 soc_info_t *si = &SOC_INFO(unit); 3723 int num_ucq, num_mcq; 3724 3725 if ((flags != BCM_COSQ_GPORT_UCAST_QUEUE_GROUP) && 3726 (flags != BCM_COSQ_GPORT_MCAST_QUEUE_GROUP) && 3727 (flags != BCM_COSQ_GPORT_ELEPHANT_UCAST_QUEUE_GROUP)) { 3728 return BCM_E_PARAM; 3729 } 3730 3731 num_ucq = _bcm_th3_get_num_ucq(unit); 3732 num_mcq = _bcm_th3_get_num_mcq(unit); 3733 3734 BCM_IF_ERROR_RETURN 3735 (_bcm_th3_cosq_localport_resolve(unit, ing_port, &local_port)); 3736 3737 if (gport) { 3738 *gport = BCM_GPORT_INVALID; 3739 } 3740 3741 *cosq = BCM_COS_INVALID; 3742 3743 BCM_IF_ERROR_RETURN 3744 (READ_COS_MAP_SELm(unit, MEM_BLOCK_ANY, local_port, 3745 &cos_map_sel_entry)); 3746 index = soc_mem_field32_get(unit, COS_MAP_SELm, &cos_map_sel_entry, 3747 SELECTf); 3748 index *= _TH3_MMU_NUM_INT_PRI; 3749 3750 entry_p = SOC_PROFILE_MEM_ENTRY(unit, _bcm_th3_cos_map_profile[unit], 3751 port_cos_map_entry_t *, 3752 index + priority); 3753 if (IS_CPU_PORT(unit, local_port)) { 3754 cpu_port_info = &_bcm_th3_cosq_cpu_port_info[unit][local_port]; 3755 } else { 3756 port_info = &_bcm_th3_cosq_port_info[unit][local_port]; 3757 } 3758 3759 switch (flags) { 3760 case BCM_COSQ_GPORT_UCAST_QUEUE_GROUP: 3761 hw_cosq = soc_mem_field32_get(unit, PORT_COS_MAPm, entry_p, 3762 UC_COS1f); 3763 if ((IS_CPU_PORT(unit, local_port) == FALSE) && (gport)) { 3764 for (ii = 0; ii < num_ucq; ii++) { 3765 node = &port_info->ucast[ii]; 3766 if (node == NULL) { 3767 return BCM_E_NOT_FOUND; 3768 } 3769 node_cosq = (node->hw_index % num_ucq); 3770 if (node && (node_cosq == hw_cosq)) { 3771 *gport = node->gport; 3772 *cosq = hw_cosq; 3773 break; 3774 } 3775 } 3776 } else { 3777 *cosq = hw_cosq; 3778 } 3779 break; 3780 case BCM_COSQ_GPORT_ELEPHANT_UCAST_QUEUE_GROUP: 3781 hw_cosq = soc_mem_field32_get(unit, PORT_COS_MAPm, entry_p, 3782 UC_COS2f); 3783 if ((IS_CPU_PORT(unit, local_port) == FALSE) && (gport)) { 3784 for (ii = 0; ii < num_ucq; ii++) { 3785 node = &port_info->ucast[ii]; 3786 if (node == NULL) { 3787 return BCM_E_NOT_FOUND; 3788 } 3789 node_cosq = (node->hw_index % num_ucq); 3790 if (node && (node_cosq == hw_cosq)) { 3791 *gport = node->gport; 3792 *cosq = hw_cosq; 3793 break; 3794 } 3795 } 3796 } else { 3797 *cosq = hw_cosq; 3798 } 3799 break; 3800 case BCM_COSQ_GPORT_MCAST_QUEUE_GROUP: 3801 hw_cosq = soc_mem_field32_get(unit, PORT_COS_MAPm, entry_p, 3802 MC_COS1f); 3803 if (gport) { 3804 if (IS_CPU_PORT(unit, local_port)) { 3805 numq = _BCM_TH3_NUM_CPU_MCAST_QUEUE; 3806 cosq_base = si->port_cosq_base[CMIC_PORT(unit)]; 3807 } else { 3808 numq = num_mcq; 3809 cosq_base = 0; 3810 } 3811 for (ii = 0; ii < numq; ii++) { 3812 if (IS_CPU_PORT(unit, local_port)) { 3813 node = &cpu_port_info->mcast[ii]; 3814 } else { 3815 node = &port_info->mcast[ii]; 3816 } 3817 if (!node) { 3818 return BCM_E_NOT_FOUND; 3819 } 3820 node_cosq = ((node->hw_index - cosq_base) % numq); 3821 if (node_cosq == hw_cosq) { 3822 *gport = node->gport; 3823 *cosq = hw_cosq; 3824 break; 3825 } 3826 } 3827 } else { 3828 *cosq = hw_cosq; 3829 } 3830 break; 3831 /* 3832 * COVERITY 3833 * 3834 * This default is unreachable. It is kept intentionally 3835 * as a defensive default for future development. 3836 */ 3837 /* coverity[dead_error_begin] */ 3838 default: 3839 return BCM_E_PARAM; 3840 } 3841 if (((gport && 3842 (*gport == BCM_GPORT_INVALID) && (*cosq == BCM_COS_INVALID))) || 3843 (*cosq == BCM_COS_INVALID)) { 3844 return BCM_E_NOT_FOUND; 3845 } 3846 3847 return BCM_E_NONE; 3848 } 3849 3850 /* 3851 * Function: 3852 * bcm_th3_cosq_mapping_get 3853 * Purpose: 3854 * Determine which COS queue a given priority currently maps to. 3855 * Parameters: 3856 * unit - (IN) unit number 3857 * gport - (IN) queue group GPORT identifier 3858 * priority - (IN) priority value to map 3859 * cosq - (OUT) COS queue to map to 3860 * Returns: 3861 * BCM_E_XXX 3862 */ 3863 int 3864 bcm_th3_cosq_mapping_get(int unit, bcm_port_t port, bcm_cos_t priority, 3865 bcm_cos_queue_t *cosq) 3866 { 3867 bcm_port_t local_port; 3868 bcm_pbmp_t pbmp; 3869 3870 if ((priority < 0) || (priority >= _TH3_MMU_NUM_INT_PRI)) { 3871 return BCM_E_PARAM; 3872 } 3873 3874 BCM_PBMP_CLEAR(pbmp); 3875 3876 if (port == -1) { 3877 BCM_PBMP_ASSIGN(pbmp, PBMP_ALL(unit)); 3878 } else { 3879 if (BCM_GPORT_IS_SET(port)) { 3880 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port) || 3881 BCM_GPORT_IS_MCAST_QUEUE_GROUP(port) || 3882 BCM_GPORT_IS_SCHEDULER(port)) { 3883 return BCM_E_PARAM; 3884 } else if (BCM_GPORT_IS_LOCAL(port)) { 3885 local_port = BCM_GPORT_LOCAL_GET(port); 3886 } else if (BCM_GPORT_IS_MODPORT(port)) { 3887 BCM_IF_ERROR_RETURN 3888 (bcm_esw_port_local_get(unit, port, &local_port)); 3889 } else { 3890 return BCM_E_PARAM; 3891 } 3892 } else { 3893 local_port = port; 3894 } 3895 3896 if (!SOC_PORT_VALID(unit, local_port)) { 3897 return BCM_E_PORT; 3898 } 3899 3900 BCM_PBMP_PORT_ADD(pbmp, local_port); 3901 } 3902 3903 PBMP_ITER(pbmp, local_port) { 3904 if (IS_LB_PORT(unit, local_port) || IS_CPU_PORT(unit, local_port)) { 3905 continue; 3906 } 3907 3908 BCM_IF_ERROR_RETURN(_bcm_th3_cosq_mapping_get(unit, local_port, 3909 priority, BCM_COSQ_GPORT_UCAST_QUEUE_GROUP, NULL, cosq)); 3910 break; 3911 } 3912 return BCM_E_NONE; 3913 } 3914 3915 3916 /* 3917 * This function is used to set shared pool 3918 * for given Ingress [Port, Priority_group] 3919 */ 3920 int 3921 _bcm_th3_cosq_ingress_sp_set_by_pg(int unit, bcm_gport_t gport, bcm_cos_queue_t pri_grp, 3922 int arg) 3923 { 3924 int local_port; 3925 uint64 rval; 3926 int profile_index; 3927 static const soc_field_t prigroup_spid_field[] = { 3928 PG0_SPIDf, PG1_SPIDf, PG2_SPIDf, PG3_SPIDf, 3929 PG4_SPIDf, PG5_SPIDf, PG6_SPIDf, PG7_SPIDf 3930 }; 3931 3932 BCM_IF_ERROR_RETURN 3933 (_bcm_th3_cosq_localport_resolve(unit, gport, &local_port)); 3934 3935 if (!SOC_PORT_VALID(unit, local_port)) { 3936 return BCM_E_PORT; 3937 } 3938 3939 if ((pri_grp < 0) || (pri_grp >= SOC_MMU_CFG_PRI_GROUP_MAX)) { 3940 return BCM_E_PARAM; 3941 } 3942 3943 COMPILER_64_ZERO(rval); 3944 SOC_IF_ERROR_RETURN 3945 (soc_reg_get(unit, MMU_THDI_ING_PORT_CONFIGr, local_port, -1, &rval)); 3946 3947 profile_index = soc_reg64_field32_get(unit, MMU_THDI_ING_PORT_CONFIGr, rval, PG_PROFILE_SELf); 3948 3949 COMPILER_64_ZERO(rval); 3950 SOC_IF_ERROR_RETURN 3951 (soc_reg64_get(unit, MMU_THDI_PG_PROFILEr, REG_PORT_ANY, profile_index, &rval)); 3952 soc_reg64_field32_set(unit, MMU_THDI_PG_PROFILEr, &rval, prigroup_spid_field[pri_grp], arg); 3953 SOC_IF_ERROR_RETURN 3954 (soc_reg64_set(unit, MMU_THDI_PG_PROFILEr, REG_PORT_ANY, profile_index, rval)); 3955 3956 3957 return BCM_E_NONE; 3958 } 3959 3960 /* 3961 * This function sets the shared limit in mmu info 3962 */ 3963 int _bcm_th3_mmu_set_shared_size(int unit, int itm, int shd_size) 3964 { 3965 _BCM_TH3_MMU_INFO(unit)->shared_limit[itm] = shd_size; 3966 return BCM_E_NONE; 3967 } 3968 3969 /* 3970 * This function retrieves the shared limit in mmu info 3971 */ 3972 int _bcm_th3_mmu_get_shared_size(int unit, int itm, int *shd_size) 3973 { 3974 *shd_size = _BCM_TH3_MMU_INFO(unit)->shared_limit[itm]; 3975 return BCM_E_NONE; 3976 } 3977 3978 3979 /* 3980 * This function is used to set headroom pool 3981 * for given Ingress [Port, Priority_group] 3982 */ 3983 int 3984 _bcm_th3_cosq_ingress_hdrm_pool_set_by_pg(int unit, bcm_gport_t gport, bcm_cos_queue_t pri_grp, 3985 int arg) 3986 { 3987 int local_port; 3988 uint64 rval; 3989 int profile_index; 3990 static const soc_field_t prigroup_hpid_field[] = { 3991 PG0_HPIDf, PG1_HPIDf, PG2_HPIDf, PG3_HPIDf, 3992 PG4_HPIDf, PG5_HPIDf, PG6_HPIDf, PG7_HPIDf 3993 }; 3994 3995 BCM_IF_ERROR_RETURN 3996 (_bcm_th3_cosq_localport_resolve(unit, gport, &local_port)); 3997 3998 if (!SOC_PORT_VALID(unit, local_port)) { 3999 return BCM_E_PORT; 4000 } 4001 4002 if ((pri_grp < 0) || (pri_grp >= SOC_MMU_CFG_PRI_GROUP_MAX)) { 4003 return BCM_E_PARAM; 4004 } 4005 4006 COMPILER_64_ZERO(rval); 4007 SOC_IF_ERROR_RETURN 4008 (soc_reg_get(unit, MMU_THDI_ING_PORT_CONFIGr, local_port, -1, &rval)); 4009 4010 profile_index = soc_reg64_field32_get(unit, MMU_THDI_ING_PORT_CONFIGr, rval, PG_PROFILE_SELf); 4011 4012 COMPILER_64_ZERO(rval); 4013 SOC_IF_ERROR_RETURN 4014 (soc_reg64_get(unit, MMU_THDI_PG_PROFILEr, REG_PORT_ANY, profile_index, &rval)); 4015 soc_reg64_field32_set(unit, MMU_THDI_PG_PROFILEr, &rval, prigroup_hpid_field[pri_grp], arg); 4016 SOC_IF_ERROR_RETURN 4017 (soc_reg64_set(unit, MMU_THDI_PG_PROFILEr, REG_PORT_ANY, profile_index, rval)); 4018 4019 4020 return BCM_E_NONE; 4021 } 4022 4023 4024 /* 4025 * This function is used to get shared pool 4026 * for given Ingress [Port, Priority_group] 4027 */ 4028 int 4029 _bcm_th3_cosq_ingress_sp_get_by_pg(int unit, bcm_gport_t gport, bcm_cos_queue_t pri_grp, 4030 int *arg) 4031 { 4032 int local_port; 4033 uint64 rval; 4034 int profile_index; 4035 static const soc_field_t prigroup_spid_field[] = { 4036 PG0_SPIDf, PG1_SPIDf, PG2_SPIDf, PG3_SPIDf, 4037 PG4_SPIDf, PG5_SPIDf, PG6_SPIDf, PG7_SPIDf 4038 }; 4039 4040 BCM_IF_ERROR_RETURN 4041 (_bcm_th3_cosq_localport_resolve(unit, gport, &local_port)); 4042 4043 if (!SOC_PORT_VALID(unit, local_port)) { 4044 return BCM_E_PORT; 4045 } 4046 4047 if ((pri_grp < 0) || (pri_grp >= SOC_MMU_CFG_PRI_GROUP_MAX)) { 4048 return BCM_E_PARAM; 4049 } 4050 4051 COMPILER_64_ZERO(rval); 4052 SOC_IF_ERROR_RETURN 4053 (soc_reg_get(unit, MMU_THDI_ING_PORT_CONFIGr, local_port, -1, &rval)); 4054 4055 profile_index = soc_reg64_field32_get(unit, MMU_THDI_ING_PORT_CONFIGr, rval, PG_PROFILE_SELf); 4056 4057 COMPILER_64_ZERO(rval); 4058 SOC_IF_ERROR_RETURN 4059 (soc_reg64_get(unit, MMU_THDI_PG_PROFILEr, REG_PORT_ANY, profile_index, &rval)); 4060 *arg = soc_reg64_field32_get(unit, MMU_THDI_PG_PROFILEr, rval, prigroup_spid_field[pri_grp]); 4061 4062 4063 return BCM_E_NONE; 4064 } 4065 4066 4067 /* 4068 * This function is used to get headroom pool 4069 * for given Ingress [Port, Priority_group] 4070 */ 4071 int 4072 _bcm_th3_cosq_ingress_hdrm_pool_get_by_pg(int unit, bcm_gport_t gport, 4073 bcm_cos_queue_t pri_grp, int *arg) 4074 { 4075 int local_port; 4076 uint64 rval; 4077 int profile_index; 4078 static const soc_field_t prigroup_hpid_field[] = { 4079 PG0_HPIDf, PG1_HPIDf, PG2_HPIDf, PG3_HPIDf, 4080 PG4_HPIDf, PG5_HPIDf, PG6_HPIDf, PG7_HPIDf 4081 }; 4082 4083 BCM_IF_ERROR_RETURN 4084 (_bcm_th3_cosq_localport_resolve(unit, gport, &local_port)); 4085 4086 if (!SOC_PORT_VALID(unit, local_port)) { 4087 return BCM_E_PORT; 4088 } 4089 4090 if ((pri_grp < 0) || (pri_grp >= SOC_MMU_CFG_PRI_GROUP_MAX)) { 4091 return BCM_E_PARAM; 4092 } 4093 4094 COMPILER_64_ZERO(rval); 4095 SOC_IF_ERROR_RETURN 4096 (soc_reg_get(unit, MMU_THDI_ING_PORT_CONFIGr, local_port, -1, &rval)); 4097 4098 profile_index = soc_reg64_field32_get(unit, MMU_THDI_ING_PORT_CONFIGr, rval, PG_PROFILE_SELf); 4099 4100 COMPILER_64_ZERO(rval); 4101 SOC_IF_ERROR_RETURN 4102 (soc_reg64_get(unit, MMU_THDI_PG_PROFILEr, REG_PORT_ANY, profile_index, &rval)); 4103 *arg = soc_reg64_field32_get(unit, MMU_THDI_PG_PROFILEr, rval, prigroup_hpid_field[pri_grp]); 4104 4105 4106 return BCM_E_NONE; 4107 } 4108 4109 4110 int 4111 _bcm_th3_cosq_egr_pool_get(int unit, bcm_gport_t gport, bcm_cos_queue_t cosq, 4112 bcm_cosq_buffer_id_t buffer, 4113 bcm_cosq_control_t type, int* arg) 4114 { 4115 bcm_port_t local_port; 4116 int startq, pool; 4117 int pipe; 4118 uint32 entry[SOC_MAX_MEM_WORDS]; 4119 soc_mem_t mem; 4120 soc_field_t fld_limit = INVALIDf; 4121 int granularity = 1; 4122 4123 if (!arg) { 4124 return BCM_E_PARAM; 4125 } 4126 4127 BCM_IF_ERROR_RETURN 4128 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4129 _BCM_TH3_COSQ_INDEX_STYLE_EGR_POOL, 4130 &local_port, &pool, NULL)); 4131 4132 SOC_IF_ERROR_RETURN(soc_port_pipe_get(unit, local_port, &pipe)); 4133 4134 if (type == bcmCosqControlEgressPool || type == bcmCosqControlUCEgressPool || 4135 type == bcmCosqControlMCEgressPool) { 4136 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 4137 if (type != bcmCosqControlEgressPool) { 4138 return BCM_E_PARAM; 4139 } 4140 /* regular unicast queue */ 4141 BCM_IF_ERROR_RETURN 4142 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4143 _BCM_TH3_COSQ_INDEX_STYLE_UCAST_QUEUE, 4144 &local_port, &startq, NULL)); 4145 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 4146 if (type != bcmCosqControlEgressPool) { 4147 return BCM_E_PARAM; 4148 } 4149 BCM_IF_ERROR_RETURN 4150 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4151 _BCM_TH3_COSQ_INDEX_STYLE_MCAST_QUEUE, 4152 &local_port, &startq, NULL)); 4153 } else { /* local port */ 4154 if (type == bcmCosqControlUCEgressPool) { 4155 BCM_IF_ERROR_RETURN 4156 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4157 _BCM_TH3_COSQ_INDEX_STYLE_UCAST_QUEUE, 4158 &local_port, &startq, NULL)); 4159 } else if (type == bcmCosqControlMCEgressPool) { 4160 BCM_IF_ERROR_RETURN 4161 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4162 _BCM_TH3_COSQ_INDEX_STYLE_MCAST_QUEUE, 4163 &local_port, &startq, NULL)); 4164 } else { 4165 if (IS_CPU_PORT(unit, local_port) || (cosq >= _bcm_th3_get_num_ucq(unit))) { 4166 BCM_IF_ERROR_RETURN 4167 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4168 _BCM_TH3_COSQ_INDEX_STYLE_MCAST_QUEUE, 4169 &local_port, &startq, NULL)); 4170 } else { 4171 BCM_IF_ERROR_RETURN 4172 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4173 _BCM_TH3_COSQ_INDEX_STYLE_UCAST_QUEUE, 4174 &local_port, &startq, NULL)); 4175 } 4176 } 4177 } 4178 mem = MMU_THDO_QUEUE_CONFIGm; 4179 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ALL, startq, entry)); 4180 *arg = soc_mem_field32_get(unit, mem, entry, SPIDf); 4181 4182 return BCM_E_NONE; 4183 } 4184 4185 /* per service pool settings */ 4186 if (type == bcmCosqControlEgressPoolSharedLimitBytes || 4187 type == bcmCosqControlEgressPoolResumeLimitBytes || 4188 type == bcmCosqControlEgressPoolYellowSharedLimitBytes || 4189 type == bcmCosqControlEgressPoolYellowResumeLimitBytes || 4190 type == bcmCosqControlEgressPoolRedSharedLimitBytes || 4191 type == bcmCosqControlEgressPoolRedResumeLimitBytes || 4192 type == bcmCosqControlEgressPoolHighCongestionLimitBytes || 4193 type == bcmCosqControlEgressPoolLowCongestionLimitBytes) { 4194 int itm; 4195 uint64 rval; 4196 soc_reg_t reg; 4197 soc_reg_t wred_cng_lmt[4] = { 4198 MMU_WRED_POOL_INST_CONG_LIMIT_0r, 4199 MMU_WRED_POOL_INST_CONG_LIMIT_1r, 4200 MMU_WRED_POOL_INST_CONG_LIMIT_2r, 4201 MMU_WRED_POOL_INST_CONG_LIMIT_3r, 4202 }; 4203 4204 switch (type) { 4205 case bcmCosqControlEgressPoolSharedLimitBytes: 4206 reg = MMU_THDO_SHARED_DB_POOL_SHARED_LIMITr; 4207 fld_limit = SHARED_LIMITf; 4208 granularity = 1; 4209 break; 4210 case bcmCosqControlEgressPoolResumeLimitBytes: 4211 reg = MMU_THDO_SHARED_DB_POOL_RESUME_LIMITr; 4212 fld_limit = RESUME_LIMITf; 4213 granularity = 8; 4214 break; 4215 case bcmCosqControlEgressPoolYellowSharedLimitBytes: 4216 reg = MMU_THDO_SHARED_DB_POOL_YELLOW_SHARED_LIMITr; 4217 fld_limit = YELLOW_SHARED_LIMITf; 4218 granularity = 8; 4219 break; 4220 case bcmCosqControlEgressPoolYellowResumeLimitBytes: 4221 reg = MMU_THDO_SHARED_DB_POOL_YELLOW_RESUME_LIMITr; 4222 fld_limit = YELLOW_RESUME_LIMITf; 4223 granularity = 8; 4224 break; 4225 case bcmCosqControlEgressPoolRedSharedLimitBytes: 4226 reg = MMU_THDO_SHARED_DB_POOL_RED_SHARED_LIMITr; 4227 fld_limit = RED_SHARED_LIMITf; 4228 granularity = 8; 4229 break; 4230 case bcmCosqControlEgressPoolRedResumeLimitBytes: 4231 reg = MMU_THDO_SHARED_DB_POOL_RED_RESUME_LIMITr; 4232 fld_limit = RED_RESUME_LIMITf; 4233 granularity = 8; 4234 break; 4235 case bcmCosqControlEgressPoolHighCongestionLimitBytes: 4236 reg = wred_cng_lmt[pool]; 4237 fld_limit = POOL_HI_CONG_LIMITf; 4238 pool = -1; 4239 granularity = 1; 4240 break; 4241 case bcmCosqControlEgressPoolLowCongestionLimitBytes: 4242 reg = wred_cng_lmt[pool]; 4243 fld_limit = POOL_LOW_CONG_LIMITf; 4244 pool = -1; 4245 granularity = 1; 4246 break; 4247 /* coverity[dead_error_begin] */ 4248 default: 4249 return BCM_E_UNAVAIL; 4250 } 4251 /* These regs are chip unique, buffer = -1 writes on both itms 4252 No need to do pipe-itm checking */ 4253 if (buffer == BCM_COSQ_BUFFER_ID_INVALID) { 4254 itm = -1; 4255 } else if (buffer < NUM_ITM(unit)) { 4256 itm = buffer; 4257 } else { 4258 return BCM_E_PARAM; 4259 } 4260 4261 SOC_IF_ERROR_RETURN(soc_tomahawk3_itm_reg_get 4262 (unit, reg, itm, itm, pool, &rval)); 4263 4264 *arg = soc_reg64_field32_get(unit, reg, rval, fld_limit); 4265 *arg = (*arg) * granularity * _TH3_MMU_BYTES_PER_CELL; 4266 4267 return BCM_E_NONE; 4268 } 4269 4270 /* per port settings: */ 4271 4272 if (type == bcmCosqControlEgressPoolLimitEnable) { 4273 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 4274 BCM_IF_ERROR_RETURN 4275 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4276 _BCM_TH3_COSQ_INDEX_STYLE_UCAST_QUEUE, 4277 &local_port, &startq, NULL)); 4278 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 4279 BCM_IF_ERROR_RETURN 4280 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4281 _BCM_TH3_COSQ_INDEX_STYLE_MCAST_QUEUE, 4282 &local_port, &startq, NULL)); 4283 } else { 4284 if (IS_CPU_PORT(unit, local_port) || (cosq >= _bcm_th3_get_num_ucq(unit))) { 4285 BCM_IF_ERROR_RETURN 4286 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4287 _BCM_TH3_COSQ_INDEX_STYLE_MCAST_QUEUE, 4288 &local_port, &startq, NULL)); 4289 } else { 4290 BCM_IF_ERROR_RETURN 4291 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4292 _BCM_TH3_COSQ_INDEX_STYLE_UCAST_QUEUE, 4293 &local_port, &startq, NULL)); 4294 } 4295 } 4296 mem = MMU_THDO_QUEUE_CONFIGm; 4297 fld_limit = LIMIT_ENABLEf; 4298 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ALL, startq, entry)); 4299 *arg = soc_mem_field32_get(unit, mem, entry, fld_limit); 4300 return BCM_E_NONE; 4301 } 4302 4303 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 4304 BCM_IF_ERROR_RETURN 4305 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4306 _BCM_TH3_COSQ_INDEX_STYLE_UCAST_QUEUE, 4307 &local_port, &startq, NULL)); 4308 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 4309 BCM_IF_ERROR_RETURN 4310 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4311 _BCM_TH3_COSQ_INDEX_STYLE_MCAST_QUEUE, 4312 &local_port, &startq, NULL)); 4313 } else { 4314 if (soc_property_get(unit, spn_PORT_UC_MC_ACCOUNTING_COMBINE, 0) == 0) { 4315 /* Need to have the UC_MC_Combine config enabled */ 4316 return BCM_E_PARAM; 4317 } 4318 if (IS_CPU_PORT(unit, local_port) || (cosq >= _bcm_th3_get_num_ucq(unit))) { 4319 BCM_IF_ERROR_RETURN 4320 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4321 _BCM_TH3_COSQ_INDEX_STYLE_MCAST_QUEUE, 4322 &local_port, &startq, NULL)); 4323 } else { 4324 BCM_IF_ERROR_RETURN 4325 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4326 _BCM_TH3_COSQ_INDEX_STYLE_UCAST_QUEUE, 4327 &local_port, &startq, NULL)); 4328 } 4329 } 4330 mem = MMU_THDO_QUEUE_CONFIGm; 4331 4332 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ALL, startq, entry)); 4333 4334 switch (type) { 4335 case bcmCosqControlEgressPoolLimitBytes: 4336 fld_limit = SHARED_LIMITf; 4337 granularity = 1; 4338 break; 4339 case bcmCosqControlEgressPoolYellowLimitBytes: 4340 fld_limit = LIMIT_YELLOWf; 4341 granularity = 8; 4342 break; 4343 case bcmCosqControlEgressPoolRedLimitBytes: 4344 fld_limit = LIMIT_REDf; 4345 granularity = 8; 4346 break; 4347 default: 4348 return BCM_E_UNAVAIL; 4349 } 4350 *arg = soc_mem_field32_get(unit, mem, entry, fld_limit); 4351 *arg = (*arg) * granularity * _TH3_MMU_BYTES_PER_CELL; 4352 4353 4354 return BCM_E_NONE; 4355 4356 4357 } 4358 4359 int 4360 _bcm_th3_cosq_egr_pool_set(int unit, bcm_gport_t gport, bcm_cos_queue_t cosq, 4361 bcm_cosq_buffer_id_t buffer, 4362 bcm_cosq_control_t type, int arg) 4363 { 4364 bcm_port_t local_port; 4365 int startq, pool; 4366 int midx; 4367 int pipe; 4368 uint32 entry[SOC_MAX_MEM_WORDS]; 4369 soc_mem_t mem; 4370 soc_mem_t mmu_thdo_per_queue_mem[] = { 4371 MMU_THDO_QUEUE_CONFIGm, 4372 MMU_THDO_Q_TO_QGRP_MAPD0m 4373 }; 4374 int mmu_thdo_per_queue_mem_cnt = 2; 4375 soc_field_t field_qspid[12] = { 4376 QUEUE0_SPIDf, QUEUE1_SPIDf, QUEUE2_SPIDf, 4377 QUEUE3_SPIDf, QUEUE4_SPIDf, QUEUE5_SPIDf, 4378 QUEUE6_SPIDf, QUEUE7_SPIDf, QUEUE8_SPIDf, 4379 QUEUE9_SPIDf, QUEUE10_SPIDf, QUEUE11_SPIDf 4380 }; 4381 soc_field_t fld_limit = INVALIDf; 4382 int idx; 4383 int granularity = 1; 4384 uint32 max_val; 4385 4386 if (arg < 0) { 4387 return BCM_E_PARAM; 4388 } 4389 4390 BCM_IF_ERROR_RETURN 4391 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4392 _BCM_TH3_COSQ_INDEX_STYLE_EGR_POOL, 4393 &local_port, &pool, NULL)); 4394 4395 SOC_IF_ERROR_RETURN(soc_port_pipe_get(unit, local_port, &pipe)); 4396 4397 if (type == bcmCosqControlEgressPool || type == bcmCosqControlUCEgressPool || 4398 type == bcmCosqControlMCEgressPool) { 4399 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 4400 if (type != bcmCosqControlEgressPool) { 4401 return BCM_E_PARAM; 4402 } 4403 /* regular unicast queue */ 4404 BCM_IF_ERROR_RETURN 4405 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4406 _BCM_TH3_COSQ_INDEX_STYLE_UCAST_QUEUE, 4407 &local_port, &startq, NULL)); 4408 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 4409 if (type != bcmCosqControlEgressPool) { 4410 return BCM_E_PARAM; 4411 } 4412 BCM_IF_ERROR_RETURN 4413 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4414 _BCM_TH3_COSQ_INDEX_STYLE_MCAST_QUEUE, 4415 &local_port, &startq, NULL)); 4416 } else { /* local port */ 4417 if (type == bcmCosqControlUCEgressPool) { 4418 BCM_IF_ERROR_RETURN 4419 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4420 _BCM_TH3_COSQ_INDEX_STYLE_UCAST_QUEUE, 4421 &local_port, &startq, NULL)); 4422 } else if (type == bcmCosqControlMCEgressPool) { 4423 BCM_IF_ERROR_RETURN 4424 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4425 _BCM_TH3_COSQ_INDEX_STYLE_MCAST_QUEUE, 4426 &local_port, &startq, NULL)); 4427 } else { 4428 if (IS_CPU_PORT(unit, local_port) || (cosq >= _bcm_th3_get_num_ucq(unit))) { 4429 BCM_IF_ERROR_RETURN 4430 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4431 _BCM_TH3_COSQ_INDEX_STYLE_MCAST_QUEUE, 4432 &local_port, &startq, NULL)); 4433 } else { 4434 BCM_IF_ERROR_RETURN 4435 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4436 _BCM_TH3_COSQ_INDEX_STYLE_UCAST_QUEUE, 4437 &local_port, &startq, NULL)); 4438 } 4439 } 4440 } 4441 4442 for (idx = 0; idx < mmu_thdo_per_queue_mem_cnt; idx++) { 4443 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mmu_thdo_per_queue_mem[idx], MEM_BLOCK_ALL, startq, entry)); 4444 soc_mem_field32_set(unit, mmu_thdo_per_queue_mem[idx], &entry, SPIDf, arg); 4445 BCM_IF_ERROR_RETURN(soc_mem_write(unit, mmu_thdo_per_queue_mem[idx], MEM_BLOCK_ALL, startq, entry)); 4446 } 4447 4448 mem = MMU_THDO_PORT_QUEUE_SERVICE_POOLm; 4449 midx = SOC_TH3_MMU_PIPED_MEM_INDEX(unit, local_port, 4450 MMU_THDO_PORT_QUEUE_SERVICE_POOLm, 0); 4451 /* CMIC has 48 queues... so not applicalble for cmic port */ 4452 if (!IS_CPU_PORT(unit, local_port)) { 4453 int cosq_idx; 4454 if (cosq == -1) { 4455 cosq_idx = 0; 4456 } else { 4457 cosq_idx = cosq; 4458 } 4459 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ALL, midx, 4460 entry)); 4461 soc_mem_field32_set(unit, mem, 4462 entry, field_qspid[cosq_idx], 4463 arg); 4464 BCM_IF_ERROR_RETURN(soc_mem_write(unit, mem, MEM_BLOCK_ALL, midx, 4465 entry)); 4466 } 4467 4468 return BCM_E_NONE; 4469 } 4470 4471 /* per service pool settings */ 4472 if (type == bcmCosqControlEgressPoolSharedLimitBytes || 4473 type == bcmCosqControlEgressPoolResumeLimitBytes || 4474 type == bcmCosqControlEgressPoolYellowSharedLimitBytes || 4475 type == bcmCosqControlEgressPoolYellowResumeLimitBytes || 4476 type == bcmCosqControlEgressPoolRedSharedLimitBytes || 4477 type == bcmCosqControlEgressPoolRedResumeLimitBytes || 4478 type == bcmCosqControlEgressPoolHighCongestionLimitBytes || 4479 type == bcmCosqControlEgressPoolLowCongestionLimitBytes) { 4480 int itm; 4481 uint64 rval; 4482 soc_reg_t reg; 4483 soc_reg_t wred_cng_lmt[4] = { 4484 MMU_WRED_POOL_INST_CONG_LIMIT_0r, 4485 MMU_WRED_POOL_INST_CONG_LIMIT_1r, 4486 MMU_WRED_POOL_INST_CONG_LIMIT_2r, 4487 MMU_WRED_POOL_INST_CONG_LIMIT_3r, 4488 }; 4489 arg = (arg + _TH3_MMU_BYTES_PER_CELL - 1) / _TH3_MMU_BYTES_PER_CELL; 4490 4491 switch (type) { 4492 case bcmCosqControlEgressPoolSharedLimitBytes: 4493 reg = MMU_THDO_SHARED_DB_POOL_SHARED_LIMITr; 4494 fld_limit = SHARED_LIMITf; 4495 granularity = 1; 4496 break; 4497 case bcmCosqControlEgressPoolResumeLimitBytes: 4498 reg = MMU_THDO_SHARED_DB_POOL_RESUME_LIMITr; 4499 fld_limit = RESUME_LIMITf; 4500 granularity = 8; 4501 break; 4502 case bcmCosqControlEgressPoolYellowSharedLimitBytes: 4503 reg = MMU_THDO_SHARED_DB_POOL_YELLOW_SHARED_LIMITr; 4504 fld_limit = YELLOW_SHARED_LIMITf; 4505 granularity = 8; 4506 break; 4507 case bcmCosqControlEgressPoolYellowResumeLimitBytes: 4508 reg = MMU_THDO_SHARED_DB_POOL_YELLOW_RESUME_LIMITr; 4509 fld_limit = YELLOW_RESUME_LIMITf; 4510 granularity = 8; 4511 break; 4512 case bcmCosqControlEgressPoolRedSharedLimitBytes: 4513 reg = MMU_THDO_SHARED_DB_POOL_RED_SHARED_LIMITr; 4514 fld_limit = RED_SHARED_LIMITf; 4515 granularity = 8; 4516 break; 4517 case bcmCosqControlEgressPoolRedResumeLimitBytes: 4518 reg = MMU_THDO_SHARED_DB_POOL_RED_RESUME_LIMITr; 4519 fld_limit = RED_RESUME_LIMITf; 4520 granularity = 8; 4521 break; 4522 case bcmCosqControlEgressPoolHighCongestionLimitBytes: 4523 reg = wred_cng_lmt[pool]; 4524 fld_limit = POOL_HI_CONG_LIMITf; 4525 pool = -1; 4526 granularity = 1; 4527 break; 4528 case bcmCosqControlEgressPoolLowCongestionLimitBytes: 4529 reg = wred_cng_lmt[pool]; 4530 fld_limit = POOL_LOW_CONG_LIMITf; 4531 pool = -1; 4532 granularity = 1; 4533 break; 4534 /* coverity[dead_error_begin] */ 4535 default: 4536 return BCM_E_UNAVAIL; 4537 } 4538 /* These regs are chip unique, buffer = -1 writes on both itms 4539 No need to do pipe-itm checking */ 4540 4541 if (buffer == BCM_COSQ_BUFFER_ID_INVALID) { 4542 itm = -1; 4543 } else if (buffer < NUM_ITM(unit)) { 4544 itm = buffer; 4545 } else { 4546 return BCM_E_PARAM; 4547 } 4548 4549 SOC_IF_ERROR_RETURN(soc_tomahawk3_itm_reg_get 4550 (unit, reg, itm, itm, pool, &rval)); 4551 4552 /* Check for min/max values */ 4553 max_val = (1 << soc_reg_field_length(unit, reg, fld_limit)) - 1; 4554 if ((arg < 0) || ((arg/granularity) > max_val)) { 4555 return BCM_E_PARAM; 4556 } else { 4557 soc_reg64_field32_set(unit, reg, &rval, fld_limit, (arg/granularity)); 4558 } 4559 4560 SOC_IF_ERROR_RETURN(soc_tomahawk3_itm_reg_set 4561 (unit, reg, itm, itm, pool, rval)); 4562 4563 return BCM_E_NONE; 4564 } 4565 4566 /* per port settings: Why is there under Pool */ 4567 if (type == bcmCosqControlEgressPoolLimitEnable) { 4568 int limit; 4569 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 4570 BCM_IF_ERROR_RETURN 4571 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4572 _BCM_TH3_COSQ_INDEX_STYLE_UCAST_QUEUE, 4573 &local_port, &startq, NULL)); 4574 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 4575 BCM_IF_ERROR_RETURN 4576 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4577 _BCM_TH3_COSQ_INDEX_STYLE_MCAST_QUEUE, 4578 &local_port, &startq, NULL)); 4579 } else { 4580 if (IS_CPU_PORT(unit, local_port) || (cosq >= _bcm_th3_get_num_ucq(unit))) { 4581 BCM_IF_ERROR_RETURN 4582 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4583 _BCM_TH3_COSQ_INDEX_STYLE_MCAST_QUEUE, 4584 &local_port, &startq, NULL)); 4585 } else { 4586 BCM_IF_ERROR_RETURN 4587 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4588 _BCM_TH3_COSQ_INDEX_STYLE_UCAST_QUEUE, 4589 &local_port, &startq, NULL)); 4590 } 4591 } 4592 mem = MMU_THDO_QUEUE_CONFIGm; 4593 fld_limit = LIMIT_ENABLEf; 4594 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ALL, startq, entry)); 4595 /* What if it is dynamic shared limit */ 4596 limit = soc_mem_field32_get(unit, mem, entry, SHARED_LIMITf); 4597 if (limit == 0) 4598 return BCM_E_PARAM; 4599 soc_mem_field32_set(unit, mem, entry, fld_limit, arg); 4600 BCM_IF_ERROR_RETURN(soc_mem_write(unit, mem, MEM_BLOCK_ALL, startq, entry)); 4601 return BCM_E_NONE; 4602 } 4603 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 4604 BCM_IF_ERROR_RETURN 4605 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4606 _BCM_TH3_COSQ_INDEX_STYLE_UCAST_QUEUE, 4607 &local_port, &startq, NULL)); 4608 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 4609 BCM_IF_ERROR_RETURN 4610 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4611 _BCM_TH3_COSQ_INDEX_STYLE_MCAST_QUEUE, 4612 &local_port, &startq, NULL)); 4613 } else { 4614 if (soc_property_get(unit, spn_PORT_UC_MC_ACCOUNTING_COMBINE, 0) == 0) { 4615 /* Need to have the UC_MC_Combine config enabled */ 4616 return BCM_E_PARAM; 4617 } 4618 if (IS_CPU_PORT(unit, local_port) || (cosq >= _bcm_th3_get_num_ucq(unit))) { 4619 BCM_IF_ERROR_RETURN 4620 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4621 _BCM_TH3_COSQ_INDEX_STYLE_MCAST_QUEUE, 4622 &local_port, &startq, NULL)); 4623 } else { 4624 BCM_IF_ERROR_RETURN 4625 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 4626 _BCM_TH3_COSQ_INDEX_STYLE_UCAST_QUEUE, 4627 &local_port, &startq, NULL)); 4628 } 4629 } 4630 4631 mem = MMU_THDO_QUEUE_CONFIGm; 4632 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ALL, startq, entry)); 4633 4634 switch (type) { 4635 case bcmCosqControlEgressPoolLimitBytes: 4636 fld_limit = SHARED_LIMITf; 4637 soc_mem_field32_set(unit, mem, entry, LIMIT_ENABLEf, 1); 4638 granularity = 1; 4639 break; 4640 case bcmCosqControlEgressPoolYellowLimitBytes: 4641 fld_limit = LIMIT_YELLOWf; 4642 granularity = 8; 4643 break; 4644 case bcmCosqControlEgressPoolRedLimitBytes: 4645 fld_limit = LIMIT_REDf; 4646 granularity = 8; 4647 break; 4648 default: 4649 return BCM_E_UNAVAIL; 4650 } 4651 /* Check for min/max values */ 4652 arg = (arg + _TH3_MMU_BYTES_PER_CELL - 1) / _TH3_MMU_BYTES_PER_CELL; 4653 max_val = (1 << soc_mem_field_length(unit, mem, fld_limit)) - 1; 4654 if ((arg < 0) || ((arg/granularity) > max_val)) { 4655 return BCM_E_PARAM; 4656 } else { 4657 soc_mem_field32_set(unit, mem, entry, fld_limit, (arg/granularity)); 4658 } 4659 BCM_IF_ERROR_RETURN(soc_mem_write(unit, mem, MEM_BLOCK_ALL, startq, entry)); 4660 4661 return BCM_E_NONE; 4662 4663 4664 } 4665 4666 /* Get pipe for a given port */ 4667 int 4668 _bcm_th3_cosq_pipe_get(int unit, bcm_gport_t gport, int *pipe) 4669 { 4670 bcm_port_t local_port; 4671 4672 if (pipe) { 4673 BCM_IF_ERROR_RETURN 4674 (_bcm_th3_cosq_localport_resolve(unit, gport, &local_port)); 4675 if (local_port < 0) { 4676 return BCM_E_PORT; 4677 } 4678 SOC_IF_ERROR_RETURN(soc_port_pipe_get(unit, local_port, pipe)); 4679 } 4680 return BCM_E_NONE; 4681 } 4682 4683 int 4684 _bcm_th3_cosq_ing_res_get(int unit, bcm_gport_t gport, bcm_cos_queue_t cosq, 4685 bcm_cosq_control_t type, int* arg) 4686 { 4687 bcm_port_t local_port; 4688 int midx; 4689 uint32 entry[SOC_MAX_MEM_WORDS]; 4690 soc_mem_t mem = INVALIDm; 4691 soc_field_t fld_limit = INVALIDf; 4692 int pipe, port_pg; 4693 int pool, granularity = 1; 4694 soc_field_t field_pgmin_limit[_TH3_MMU_NUM_PG] = { 4695 PG0_MIN_LIMITf, PG1_MIN_LIMITf, PG2_MIN_LIMITf, 4696 PG3_MIN_LIMITf, PG4_MIN_LIMITf, PG5_MIN_LIMITf, 4697 PG6_MIN_LIMITf, PG7_MIN_LIMITf}; 4698 /* soc_field_t field_use_portsp[_TH3_MMU_NUM_PG] = { 4699 PG0_USE_PORTSP_MINf, PG1_USE_PORTSP_MINf, PG2_USE_PORTSP_MINf, 4700 PG3_USE_PORTSP_MINf, PG4_USE_PORTSP_MINf, PG5_USE_PORTSP_MINf, 4701 PG6_USE_PORTSP_MINf, PG7_USE_PORTSP_MINf}; */ 4702 soc_field_t field_pghdrm_limit[_TH3_MMU_NUM_PG] = { 4703 PG0_HDRM_LIMITf, PG1_HDRM_LIMITf, PG2_HDRM_LIMITf, 4704 PG3_HDRM_LIMITf, PG4_HDRM_LIMITf, PG5_HDRM_LIMITf, 4705 PG6_HDRM_LIMITf, PG7_HDRM_LIMITf}; 4706 soc_field_t field_pgshared_limit[_TH3_MMU_NUM_PG] = { 4707 PG0_SHARED_LIMITf, PG1_SHARED_LIMITf, PG2_SHARED_LIMITf, 4708 PG3_SHARED_LIMITf, PG4_SHARED_LIMITf, PG5_SHARED_LIMITf, 4709 PG6_SHARED_LIMITf, PG7_SHARED_LIMITf}; 4710 soc_field_t field_pgreset_floor[_TH3_MMU_NUM_PG] = { 4711 PG0_RESET_FLOORf, PG1_RESET_FLOORf, PG2_RESET_FLOORf, 4712 PG3_RESET_FLOORf, PG4_RESET_FLOORf, PG5_RESET_FLOORf, 4713 PG6_RESET_FLOORf, PG7_RESET_FLOORf}; 4714 soc_field_t field_sp_min[_TH3_MMU_NUM_POOL] = { 4715 PORTSP0_MIN_LIMITf, PORTSP1_MIN_LIMITf, 4716 PORTSP2_MIN_LIMITf, PORTSP3_MIN_LIMITf}; 4717 soc_field_t field_sp_shared[_TH3_MMU_NUM_POOL] = { 4718 PORTSP0_SHARED_LIMITf, PORTSP1_SHARED_LIMITf, 4719 PORTSP2_SHARED_LIMITf, PORTSP3_SHARED_LIMITf}; 4720 soc_field_t field_sp_resume[_TH3_MMU_NUM_POOL] = { 4721 PORTSP0_RESUME_LIMITf, PORTSP1_RESUME_LIMITf, 4722 PORTSP2_RESUME_LIMITf, PORTSP3_RESUME_LIMITf}; 4723 soc_field_t field_pgreset_offset[_TH3_MMU_NUM_PG] = { 4724 PG0_RESET_OFFSETf, PG1_RESET_OFFSETf, PG2_RESET_OFFSETf, 4725 PG3_RESET_OFFSETf, PG4_RESET_OFFSETf, PG5_RESET_OFFSETf, 4726 PG6_RESET_OFFSETf, PG7_RESET_OFFSETf}; 4727 4728 if (!arg) { 4729 return BCM_E_PARAM; 4730 } 4731 4732 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport) || 4733 BCM_GPORT_IS_SCHEDULER(gport) || 4734 BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 4735 return BCM_E_PARAM; 4736 } 4737 4738 BCM_IF_ERROR_RETURN 4739 (_bcm_th3_cosq_localport_resolve(unit, gport, &local_port)); 4740 if (!SOC_PORT_VALID(unit, local_port)) { 4741 return BCM_E_PORT; 4742 } 4743 4744 4745 if ((cosq < 0) || (cosq >= _TH3_MMU_NUM_PG)) { 4746 return BCM_E_PARAM; 4747 } 4748 port_pg = cosq; 4749 4750 BCM_IF_ERROR_RETURN 4751 (_bcm_th3_cosq_pipe_get(unit, gport, &pipe)); 4752 4753 BCM_IF_ERROR_RETURN 4754 (_bcm_th3_cosq_ingress_sp_get_by_pg(unit, gport, port_pg, &pool)); 4755 4756 sal_memset(&entry, 0, sizeof(entry)); 4757 if (type == bcmCosqControlIngressPortPGSharedLimitBytes) { 4758 mem = SOC_MEM_UNIQUE_ACC(unit, MMU_THDI_PORT_PG_SHARED_CONFIGm)[pipe]; 4759 midx = SOC_TH3_MMU_PIPED_MEM_INDEX(unit, local_port, 4760 MMU_THDI_PORT_PG_SHARED_CONFIGm, 0); 4761 } else if (type == bcmCosqControlIngressPortPGMinLimitBytes) { 4762 mem = SOC_MEM_UNIQUE_ACC(unit, MMU_THDI_PORT_PG_MIN_CONFIGm)[pipe]; 4763 midx = SOC_TH3_MMU_PIPED_MEM_INDEX(unit, local_port, 4764 MMU_THDI_PORT_PG_MIN_CONFIGm, 0); 4765 } else if (type == bcmCosqControlIngressPortPGHeadroomLimitBytes) { 4766 mem = SOC_MEM_UNIQUE_ACC(unit, MMU_THDI_PORT_PG_HDRM_CONFIGm)[pipe]; 4767 midx = SOC_TH3_MMU_PIPED_MEM_INDEX(unit, local_port, 4768 MMU_THDI_PORT_PG_HDRM_CONFIGm, 0); 4769 } else if ((type == bcmCosqControlIngressPortPGResetFloorBytes)|| 4770 (type == bcmCosqControlIngressPortPGResetOffsetBytes)) { 4771 mem = SOC_MEM_UNIQUE_ACC(unit, MMU_THDI_PORT_PG_RESUME_CONFIGm)[pipe]; 4772 midx = SOC_TH3_MMU_PIPED_MEM_INDEX(unit, local_port, 4773 MMU_THDI_PORT_PG_RESUME_CONFIGm, 0); 4774 } else if ((type == bcmCosqControlIngressPortPoolMinLimitBytes) || 4775 (type == bcmCosqControlIngressPortPoolSharedLimitBytes) || 4776 (type == bcmCosqControlIngressPortPoolResumeLimitBytes)) { 4777 mem = SOC_MEM_UNIQUE_ACC(unit, MMU_THDI_PORTSP_CONFIGm)[pipe]; 4778 midx = SOC_TH3_MMU_PIPED_MEM_INDEX(unit, local_port, MMU_THDI_PORTSP_CONFIGm, 0); 4779 } else { 4780 return BCM_E_UNAVAIL; 4781 } 4782 4783 if (midx < 0) { 4784 return BCM_E_PARAM; 4785 } 4786 4787 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ALL, midx, entry)); 4788 4789 switch (type) { 4790 case bcmCosqControlIngressPortPGSharedLimitBytes: 4791 fld_limit = field_pgshared_limit[port_pg]; 4792 granularity = 1; 4793 break; 4794 case bcmCosqControlIngressPortPGMinLimitBytes: 4795 fld_limit = field_pgmin_limit[port_pg]; 4796 granularity = 1; 4797 break; 4798 case bcmCosqControlIngressPortPoolMinLimitBytes: 4799 fld_limit = field_sp_min[pool]; 4800 granularity = 1; 4801 break; 4802 case bcmCosqControlIngressPortPoolSharedLimitBytes: 4803 fld_limit = field_sp_shared[pool]; 4804 granularity = 1; 4805 break; 4806 case bcmCosqControlIngressPortPoolResumeLimitBytes: 4807 fld_limit = field_sp_resume[pool]; 4808 granularity = 1; 4809 break; 4810 case bcmCosqControlIngressPortPGHeadroomLimitBytes: 4811 fld_limit = field_pghdrm_limit[port_pg]; 4812 granularity = 1; 4813 break; 4814 case bcmCosqControlIngressPortPGResetFloorBytes: 4815 fld_limit = field_pgreset_floor[port_pg]; 4816 granularity = 1; 4817 break; 4818 case bcmCosqControlIngressPortPGResetOffsetBytes: 4819 fld_limit = field_pgreset_offset[port_pg]; 4820 granularity = 1; 4821 break; 4822 /* 4823 * COVERITY 4824 * 4825 * This default is unreachable. It is kept intentionally 4826 * as a defensive default for future development. 4827 */ 4828 /* coverity[dead_error_begin] */ 4829 default: 4830 return BCM_E_UNAVAIL; 4831 } 4832 4833 *arg = soc_mem_field32_get(unit, mem, entry, fld_limit); 4834 *arg = (*arg) * granularity * _TH3_MMU_BYTES_PER_CELL; 4835 4836 return BCM_E_NONE; 4837 } 4838 4839 4840 int 4841 _bcm_th3_cosq_ing_res_set(int unit, bcm_gport_t gport, bcm_cos_queue_t cosq, 4842 bcm_cosq_control_t type, int arg) 4843 { 4844 bcm_port_t local_port; 4845 int midx; 4846 uint32 max_val; 4847 uint32 entry[SOC_MAX_MEM_WORDS]; 4848 soc_mem_t mem = INVALIDm; 4849 soc_field_t fld_limit = INVALIDf; 4850 int pipe, port_pg; 4851 int pool, granularity = 1; 4852 int shd_size[_TH3_ITMS_PER_DEV], cur_val; 4853 soc_field_t field_pgmin_limit[_TH3_MMU_NUM_PG] = { 4854 PG0_MIN_LIMITf, PG1_MIN_LIMITf, PG2_MIN_LIMITf, 4855 PG3_MIN_LIMITf, PG4_MIN_LIMITf, PG5_MIN_LIMITf, 4856 PG6_MIN_LIMITf, PG7_MIN_LIMITf}; 4857 /* soc_field_t field_use_portsp[_TH3_MMU_NUM_PG] = { 4858 PG0_USE_PORTSP_MINf, PG1_USE_PORTSP_MINf, PG2_USE_PORTSP_MINf, 4859 PG3_USE_PORTSP_MINf, PG4_USE_PORTSP_MINf, PG5_USE_PORTSP_MINf, 4860 PG6_USE_PORTSP_MINf, PG7_USE_PORTSP_MINf}; */ 4861 soc_field_t field_pghdrm_limit[_TH3_MMU_NUM_PG] = { 4862 PG0_HDRM_LIMITf, PG1_HDRM_LIMITf, PG2_HDRM_LIMITf, 4863 PG3_HDRM_LIMITf, PG4_HDRM_LIMITf, PG5_HDRM_LIMITf, 4864 PG6_HDRM_LIMITf, PG7_HDRM_LIMITf}; 4865 soc_field_t field_pgshared_limit[_TH3_MMU_NUM_PG] = { 4866 PG0_SHARED_LIMITf, PG1_SHARED_LIMITf, PG2_SHARED_LIMITf, 4867 PG3_SHARED_LIMITf, PG4_SHARED_LIMITf, PG5_SHARED_LIMITf, 4868 PG6_SHARED_LIMITf, PG7_SHARED_LIMITf}; 4869 soc_field_t field_pgreset_floor[_TH3_MMU_NUM_PG] = { 4870 PG0_RESET_FLOORf, PG1_RESET_FLOORf, PG2_RESET_FLOORf, 4871 PG3_RESET_FLOORf, PG4_RESET_FLOORf, PG5_RESET_FLOORf, 4872 PG6_RESET_FLOORf, PG7_RESET_FLOORf}; 4873 soc_field_t field_sp_min[_TH3_MMU_NUM_POOL] = { 4874 PORTSP0_MIN_LIMITf, PORTSP1_MIN_LIMITf, 4875 PORTSP2_MIN_LIMITf, PORTSP3_MIN_LIMITf}; 4876 soc_field_t field_sp_shared[_TH3_MMU_NUM_POOL] = { 4877 PORTSP0_SHARED_LIMITf, PORTSP1_SHARED_LIMITf, 4878 PORTSP2_SHARED_LIMITf, PORTSP3_SHARED_LIMITf}; 4879 soc_field_t field_sp_resume[_TH3_MMU_NUM_POOL] = { 4880 PORTSP0_RESUME_LIMITf, PORTSP1_RESUME_LIMITf, 4881 PORTSP2_RESUME_LIMITf, PORTSP3_RESUME_LIMITf}; 4882 soc_field_t field_pgreset_offset[_TH3_MMU_NUM_PG] = { 4883 PG0_RESET_OFFSETf, PG1_RESET_OFFSETf, PG2_RESET_OFFSETf, 4884 PG3_RESET_OFFSETf, PG4_RESET_OFFSETf, PG5_RESET_OFFSETf, 4885 PG6_RESET_OFFSETf, PG7_RESET_OFFSETf}; 4886 4887 4888 if (arg < 0) { 4889 return BCM_E_PARAM; 4890 } 4891 4892 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport) || 4893 BCM_GPORT_IS_SCHEDULER(gport) || 4894 BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 4895 return BCM_E_PARAM; 4896 } 4897 4898 arg = (arg + _TH3_MMU_BYTES_PER_CELL - 1) / _TH3_MMU_BYTES_PER_CELL; 4899 BCM_IF_ERROR_RETURN 4900 (_bcm_th3_cosq_localport_resolve(unit, gport, &local_port)); 4901 if (!SOC_PORT_VALID(unit, local_port)) { 4902 return BCM_E_PORT; 4903 } 4904 4905 4906 if ((cosq < 0) || (cosq >= _TH3_MMU_NUM_PG)) { 4907 return BCM_E_PARAM; 4908 } 4909 port_pg = cosq; 4910 4911 BCM_IF_ERROR_RETURN 4912 (_bcm_th3_cosq_pipe_get(unit, gport, &pipe)); 4913 4914 BCM_IF_ERROR_RETURN 4915 (_bcm_th3_cosq_ingress_sp_get_by_pg(unit, gport, port_pg, &pool)); 4916 4917 sal_memset(&entry, 0, sizeof(entry)); 4918 if (type == bcmCosqControlIngressPortPGSharedLimitBytes) { 4919 mem = SOC_MEM_UNIQUE_ACC(unit, MMU_THDI_PORT_PG_SHARED_CONFIGm)[pipe]; 4920 midx = SOC_TH3_MMU_PIPED_MEM_INDEX(unit, local_port, 4921 MMU_THDI_PORT_PG_SHARED_CONFIGm, 0); 4922 } else if (type == bcmCosqControlIngressPortPGMinLimitBytes) { 4923 mem = SOC_MEM_UNIQUE_ACC(unit, MMU_THDI_PORT_PG_MIN_CONFIGm)[pipe]; 4924 midx = SOC_TH3_MMU_PIPED_MEM_INDEX(unit, local_port, 4925 MMU_THDI_PORT_PG_MIN_CONFIGm, 0); 4926 } else if (type == bcmCosqControlIngressPortPGHeadroomLimitBytes) { 4927 mem = SOC_MEM_UNIQUE_ACC(unit, MMU_THDI_PORT_PG_HDRM_CONFIGm)[pipe]; 4928 midx = SOC_TH3_MMU_PIPED_MEM_INDEX(unit, local_port, 4929 MMU_THDI_PORT_PG_HDRM_CONFIGm, 0); 4930 } else if ((type == bcmCosqControlIngressPortPGResetFloorBytes) || 4931 (type == bcmCosqControlIngressPortPGResetOffsetBytes)) { 4932 mem = SOC_MEM_UNIQUE_ACC(unit, MMU_THDI_PORT_PG_RESUME_CONFIGm)[pipe]; 4933 midx = SOC_TH3_MMU_PIPED_MEM_INDEX(unit, local_port, 4934 MMU_THDI_PORT_PG_RESUME_CONFIGm, 0); 4935 } else if ((type == bcmCosqControlIngressPortPoolMinLimitBytes) || 4936 (type == bcmCosqControlIngressPortPoolSharedLimitBytes) || 4937 (type == bcmCosqControlIngressPortPoolResumeLimitBytes)) { 4938 mem = SOC_MEM_UNIQUE_ACC(unit, MMU_THDI_PORTSP_CONFIGm)[pipe]; 4939 midx = SOC_TH3_MMU_PIPED_MEM_INDEX(unit, local_port, MMU_THDI_PORTSP_CONFIGm, 0); 4940 } 4941 else { 4942 return BCM_E_UNAVAIL; 4943 } 4944 4945 if (midx < 0) { 4946 return BCM_E_PARAM; 4947 } 4948 4949 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ALL, midx, entry)); 4950 4951 switch (type) { 4952 case bcmCosqControlIngressPortPGSharedLimitBytes: 4953 fld_limit = field_pgshared_limit[port_pg]; 4954 granularity = 1; 4955 break; 4956 case bcmCosqControlIngressPortPGMinLimitBytes: 4957 fld_limit = field_pgmin_limit[port_pg]; 4958 granularity = 1; 4959 break; 4960 case bcmCosqControlIngressPortPoolMinLimitBytes: 4961 fld_limit = field_sp_min[pool]; 4962 granularity = 1; 4963 break; 4964 case bcmCosqControlIngressPortPoolSharedLimitBytes: 4965 fld_limit = field_sp_shared[pool]; 4966 granularity = 1; 4967 break; 4968 case bcmCosqControlIngressPortPoolResumeLimitBytes: 4969 fld_limit = field_sp_resume[pool]; 4970 granularity = 1; 4971 break; 4972 case bcmCosqControlIngressPortPGHeadroomLimitBytes: 4973 fld_limit = field_pghdrm_limit[port_pg]; 4974 granularity = 1; 4975 break; 4976 case bcmCosqControlIngressPortPGResetFloorBytes: 4977 fld_limit = field_pgreset_floor[port_pg]; 4978 granularity = 1; 4979 break; 4980 case bcmCosqControlIngressPortPGResetOffsetBytes: 4981 fld_limit = field_pgreset_offset[port_pg]; 4982 granularity = 1; 4983 break; 4984 /* 4985 * COVERITY 4986 * 4987 * This default is unreachable. It is kept intentionally 4988 * as a defensive default for future development. 4989 */ 4990 /* coverity[dead_error_begin] */ 4991 default: 4992 return BCM_E_UNAVAIL; 4993 } 4994 4995 /* Check for min/max values */ 4996 max_val = (1 << soc_mem_field_length(unit, mem, fld_limit)) - 1; 4997 if ((arg < 0) || ((arg/granularity) > max_val)) { 4998 return BCM_E_PARAM; 4999 } 5000 5001 /* guarantee limits need adjust shared limits */ 5002 if ((type == bcmCosqControlIngressPortPGMinLimitBytes) || 5003 (type == bcmCosqControlIngressPortPGHeadroomLimitBytes)) { 5004 int itm, itm_map; 5005 int delta[_TH3_ITMS_PER_DEV] = {0}, update; 5006 5007 cur_val = soc_mem_field32_get(unit, mem, entry, fld_limit); 5008 sal_memcpy(shd_size, _BCM_TH3_MMU_INFO(unit)->shared_limit, 5009 sizeof(shd_size)); 5010 5011 /* adjustment delta */ 5012 itm_map = SOC_INFO(unit).ipipe_itm_map[pipe]; 5013 for (itm = 0; itm < _TH3_ITMS_PER_DEV; itm++) { 5014 if (itm_map & (1 << itm)) { 5015 delta[itm] = ((arg / granularity) - cur_val) * granularity; 5016 } 5017 } 5018 5019 /* shared limits to be decreased */ 5020 for (itm = 0, update = 0; itm < _TH3_ITMS_PER_DEV; itm ++) { 5021 if ((itm_map & (1 << itm)) && (delta[itm] > 0)) { 5022 /* no space to decrease shared limit */ 5023 if (delta[itm] > shd_size[itm]) { 5024 return BCM_E_RESOURCE; 5025 } 5026 shd_size[itm] -= delta[itm]; 5027 update = 1; 5028 } 5029 } 5030 if (update) { 5031 /* Decrease shared limits */ 5032 BCM_IF_ERROR_RETURN 5033 (soc_th3_mmu_config_res_limits_update(unit, delta, pool, 1)); 5034 } 5035 5036 /* set new guarantee */ 5037 /* the hw value may be changed by soc_th3_mmu_config_res_limits_update 5038 * so read the register again in order to keep consistent */ 5039 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ALL, midx, entry)); 5040 soc_mem_field32_set(unit, mem, entry, fld_limit, (arg/granularity)); 5041 BCM_IF_ERROR_RETURN(soc_mem_write(unit, mem, MEM_BLOCK_ALL, midx, entry)); 5042 5043 /* shared limits to be increased */ 5044 for (itm = 0, update = 0; itm < _TH3_ITMS_PER_DEV; itm ++) { 5045 if ((itm_map & (1 << itm)) && (delta[itm] < 0)) { 5046 shd_size[itm] -= delta[itm]; 5047 update = 1; 5048 } 5049 } 5050 if (update) { 5051 /* Increase shared limits */ 5052 BCM_IF_ERROR_RETURN 5053 (soc_th3_mmu_config_res_limits_update(unit, delta, pool, 0)); 5054 } 5055 sal_memcpy(_BCM_TH3_MMU_INFO(unit)->shared_limit, shd_size, 5056 sizeof(shd_size)); 5057 5058 /* In the case of PG Headroom limit, update headroom pool limit */ 5059 if (type == bcmCosqControlIngressPortPGHeadroomLimitBytes) { 5060 uint32 rval = 0; 5061 int cur_hdrm = 0; 5062 for (itm = 0, update = 0; itm < _TH3_ITMS_PER_DEV; itm ++) { 5063 if (itm_map & (1 << itm)) { 5064 SOC_IF_ERROR_RETURN( 5065 soc_tomahawk3_itm_reg32_get(unit, 5066 MMU_THDI_HDRM_BUFFER_CELL_LIMIT_HPr, itm, itm, pool, &rval)); 5067 cur_hdrm = soc_reg_field_get(unit, MMU_THDI_HDRM_BUFFER_CELL_LIMIT_HPr, 5068 rval, LIMITf); 5069 cur_hdrm += delta[itm]; 5070 if (cur_hdrm < 0) { 5071 return BCM_E_PARAM; 5072 } 5073 soc_reg_field_set(unit, MMU_THDI_HDRM_BUFFER_CELL_LIMIT_HPr, 5074 &rval, LIMITf, cur_hdrm); 5075 SOC_IF_ERROR_RETURN( 5076 soc_tomahawk3_itm_reg32_set(unit, 5077 MMU_THDI_HDRM_BUFFER_CELL_LIMIT_HPr, itm, itm, pool, rval)); 5078 } 5079 } 5080 } 5081 } else { 5082 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ALL, midx, entry)); 5083 soc_mem_field32_set(unit, mem, entry, fld_limit, (arg/granularity)); 5084 BCM_IF_ERROR_RETURN(soc_mem_write(unit, mem, MEM_BLOCK_ALL, midx, entry)); 5085 } 5086 5087 return BCM_E_NONE; 5088 } 5089 5090 int 5091 _bcm_th3_cosq_egr_queue_set(int unit, bcm_gport_t gport, bcm_cos_queue_t cosq, 5092 bcm_cosq_control_t type, int arg) 5093 { 5094 bcm_port_t local_port; 5095 /* int pipe; */ 5096 int startq; 5097 uint32 max_val; 5098 uint32 entry[SOC_MAX_MEM_WORDS]; 5099 soc_mem_t mem = INVALIDm; 5100 soc_field_t fld_limit = INVALIDf; 5101 int granularity = 1; 5102 int from_cos, to_cos, ci; 5103 int shd_size[_TH3_ITMS_PER_DEV]; 5104 int cur_val; 5105 int limit; 5106 int disable_queuing = 0; 5107 5108 if (arg < 0) { 5109 return BCM_E_PARAM; 5110 } 5111 5112 arg = (arg + _TH3_MMU_BYTES_PER_CELL - 1) / _TH3_MMU_BYTES_PER_CELL; 5113 5114 if ((type == bcmCosqControlEgressUCQueueMinLimitBytes) || 5115 (type == bcmCosqControlEgressUCQueueSharedLimitBytes) || 5116 (type == bcmCosqControlEgressUCQueueResumeOffsetBytes)) { 5117 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 5118 BCM_IF_ERROR_RETURN 5119 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 5120 _BCM_TH3_COSQ_INDEX_STYLE_UCAST_QUEUE, 5121 &local_port, &startq, NULL)); 5122 /* SOC_IF_ERROR_RETURN 5123 (soc_port_pipe_get(unit, local_port, &pipe)); */ 5124 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 5125 return BCM_E_PARAM; 5126 } 5127 else { 5128 if (cosq == BCM_COS_INVALID) { 5129 from_cos = to_cos = 0; 5130 } else { 5131 from_cos = to_cos = cosq; 5132 } 5133 5134 BCM_IF_ERROR_RETURN 5135 (_bcm_th3_cosq_localport_resolve(unit, gport, &local_port)); 5136 if (local_port < 0) { 5137 return BCM_E_PORT; 5138 } 5139 /* SOC_IF_ERROR_RETURN(soc_port_pipe_get(unit, local_port, &pipe)); */ 5140 for (ci = from_cos; ci <= to_cos; ci++) { 5141 BCM_IF_ERROR_RETURN 5142 (_bcm_th3_cosq_index_resolve 5143 (unit, local_port, ci, _BCM_TH3_COSQ_INDEX_STYLE_UCAST_QUEUE, 5144 NULL, &startq, NULL)); 5145 } 5146 } 5147 if (type == bcmCosqControlEgressUCQueueResumeOffsetBytes) { 5148 mem = MMU_THDO_QUEUE_RESUME_OFFSETm; 5149 } else { 5150 mem = MMU_THDO_QUEUE_CONFIGm; 5151 } 5152 } else if ((type == bcmCosqControlEgressMCQueueMinLimitBytes) || 5153 (type == bcmCosqControlEgressMCQueueResumeOffsetBytes) || 5154 (type == bcmCosqControlEgressMCQueueSharedLimitBytes)) { 5155 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 5156 return BCM_E_PARAM; 5157 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 5158 BCM_IF_ERROR_RETURN 5159 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 5160 _BCM_TH3_COSQ_INDEX_STYLE_MCAST_QUEUE, 5161 &local_port, &startq, NULL)); 5162 /* SOC_IF_ERROR_RETURN(soc_port_pipe_get(unit, local_port, &pipe));*/ 5163 } 5164 else { 5165 if (cosq == BCM_COS_INVALID) { 5166 from_cos = to_cos = 0; 5167 } else { 5168 from_cos = to_cos = cosq; 5169 } 5170 5171 BCM_IF_ERROR_RETURN 5172 (_bcm_th3_cosq_localport_resolve(unit, gport, &local_port)); 5173 if (local_port < 0) { 5174 return BCM_E_PORT; 5175 } 5176 /* SOC_IF_ERROR_RETURN(soc_port_pipe_get(unit, local_port, &pipe)); */ 5177 for (ci = from_cos; ci <= to_cos; ci++) { 5178 BCM_IF_ERROR_RETURN 5179 (_bcm_th3_cosq_index_resolve 5180 (unit, local_port, ci, _BCM_TH3_COSQ_INDEX_STYLE_MCAST_QUEUE, 5181 NULL, &startq, NULL)); 5182 } 5183 } 5184 if (type == bcmCosqControlEgressMCQueueResumeOffsetBytes) { 5185 mem = MMU_THDO_QUEUE_RESUME_OFFSETm; 5186 } else { 5187 mem = MMU_THDO_QUEUE_CONFIGm; 5188 } 5189 } else { 5190 return BCM_E_PARAM; 5191 } 5192 5193 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ALL, startq, entry)); 5194 5195 switch (type) { 5196 case bcmCosqControlEgressUCQueueSharedLimitBytes: 5197 case bcmCosqControlEgressMCQueueSharedLimitBytes: 5198 fld_limit = SHARED_LIMITf; 5199 5200 /* Set MMU_THDO_QUEUE_CONFIG.DISABLE_QUEUING to 1 when both MIN 5201 * and SHARED LIMIT are 0. Set it to 0 when either MIN or SHARED LIMIT 5202 * is non-zero. 5203 */ 5204 limit = soc_mem_field32_get(unit, mem, entry, MIN_LIMITf); 5205 if (arg == 0 && limit == 0) { 5206 disable_queuing = 1; 5207 } else if (arg != 0 || limit != 0) { 5208 disable_queuing = 0; 5209 } 5210 granularity = 1; 5211 break; 5212 case bcmCosqControlEgressUCQueueMinLimitBytes: 5213 case bcmCosqControlEgressMCQueueMinLimitBytes: 5214 fld_limit = MIN_LIMITf; 5215 5216 /* Set MMU_THDO_QUEUE_CONFIG.DISABLE_QUEUING to 1 when both MIN 5217 * and SHARED LIMIT are 0. Set it to 0 when either MIN or 5218 * SHARED LIMIT is non-zero 5219 */ 5220 limit = soc_mem_field32_get(unit, mem, entry, SHARED_LIMITf); 5221 if (arg == 0 && limit == 0) { 5222 disable_queuing = 1; 5223 } else if (arg != 0 || limit != 0) { 5224 disable_queuing = 0; 5225 } 5226 5227 granularity = 1; 5228 break; 5229 case bcmCosqControlEgressUCQueueResumeOffsetBytes: 5230 case bcmCosqControlEgressMCQueueResumeOffsetBytes: 5231 fld_limit = RESUME_OFFSETf; 5232 granularity = 8; 5233 break; 5234 default: 5235 return BCM_E_UNAVAIL; 5236 } 5237 5238 /* Check for min/max values */ 5239 max_val = (1 << soc_mem_field_length(unit, mem, fld_limit)) - 1; 5240 if ((arg < 0) || ((arg/granularity) > max_val)) { 5241 return BCM_E_PARAM; 5242 } 5243 5244 /* guarantee limits need adjust shared limits */ 5245 if ((type == bcmCosqControlEgressUCQueueMinLimitBytes) || 5246 (type == bcmCosqControlEgressMCQueueMinLimitBytes)) { 5247 int itm, itm_map; 5248 int delta[_TH3_ITMS_PER_DEV] = {0}, update; 5249 int pool; 5250 itm_map = SOC_INFO(unit).itm_map; 5251 BCM_IF_ERROR_RETURN(_bcm_th3_cosq_egr_pool_get(unit, gport, 5252 cosq, -1, bcmCosqControlEgressPool,&pool)); 5253 5254 cur_val = soc_mem_field32_get(unit, mem, entry, fld_limit); 5255 sal_memcpy(shd_size, _BCM_TH3_MMU_INFO(unit)->shared_limit, 5256 sizeof(shd_size)); 5257 5258 /* adjustment delta */ 5259 for (itm = 0; itm < NUM_ITM(unit); itm ++) { 5260 if (itm_map & (1 << itm)) { 5261 delta[itm] = ((arg / granularity) - cur_val) * granularity; 5262 } 5263 } 5264 5265 /* shared limits to be decreased */ 5266 for (itm = 0, update = 0; itm < NUM_ITM(unit); itm ++) { 5267 if (itm_map & (1 << itm)) { 5268 if (delta[itm] > 0) { 5269 /* no space to decrease shared limit */ 5270 if (delta[itm] > shd_size[itm]) { 5271 return BCM_E_RESOURCE; 5272 } 5273 shd_size[itm] -= delta[itm]; 5274 update = 1; 5275 } 5276 } 5277 } 5278 if (update) { 5279 BCM_IF_ERROR_RETURN 5280 (soc_th3_mmu_config_res_limits_update(unit, delta, pool, 1)); 5281 } 5282 5283 /* set new guarantee */ 5284 /* the hw value may be changed by soc_th3_mmu_config_res_limits_update 5285 * so read the register again in order to keep consistent */ 5286 BCM_IF_ERROR_RETURN 5287 (soc_mem_read(unit, mem, MEM_BLOCK_ALL, startq, entry)); 5288 soc_mem_field32_set(unit, mem, entry, fld_limit, (arg/granularity)); 5289 BCM_IF_ERROR_RETURN 5290 (soc_mem_write(unit, mem, MEM_BLOCK_ALL, startq, entry)); 5291 5292 /* shared limits to be increased */ 5293 for (itm = 0, update = 0; itm < NUM_ITM(unit); itm ++) { 5294 if (itm_map & (1 << itm)) { 5295 if (delta[itm] < 0) { 5296 shd_size[itm] -= delta[itm]; 5297 update = 1; 5298 } 5299 } 5300 } 5301 if (update) { 5302 BCM_IF_ERROR_RETURN 5303 (soc_th3_mmu_config_res_limits_update(unit, delta, pool, 0)); 5304 } 5305 5306 sal_memcpy(_BCM_TH3_MMU_INFO(unit)->shared_limit, shd_size, 5307 sizeof(shd_size)); 5308 } else { 5309 soc_mem_field32_set(unit, mem, entry, fld_limit, (arg/granularity)); 5310 BCM_IF_ERROR_RETURN 5311 (soc_mem_write(unit, mem, MEM_BLOCK_ALL, startq, entry)); 5312 } 5313 5314 /* limit enable */ 5315 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ALL, startq, entry)); 5316 5317 if ((type == bcmCosqControlEgressUCQueueMinLimitBytes) || 5318 (type == bcmCosqControlEgressUCQueueSharedLimitBytes)) { 5319 soc_mem_field32_set(unit, mem, entry, DISABLE_QUEUINGf, disable_queuing); 5320 } 5321 5322 if ((type == bcmCosqControlEgressUCQueueSharedLimitBytes) || 5323 (type == bcmCosqControlEgressMCQueueSharedLimitBytes)) { 5324 soc_mem_field32_set(unit, mem, entry, LIMIT_ENABLEf, 1); 5325 BCM_IF_ERROR_RETURN(soc_mem_write(unit, mem, MEM_BLOCK_ALL, startq, entry)); 5326 } 5327 5328 return BCM_E_NONE; 5329 } 5330 5331 5332 5333 int 5334 _bcm_th3_cosq_egr_queue_get(int unit, bcm_gport_t gport, bcm_cos_queue_t cosq, 5335 bcm_cosq_control_t type, int* arg) 5336 { 5337 bcm_port_t local_port; 5338 int pipe, startq; 5339 uint32 entry[SOC_MAX_MEM_WORDS]; 5340 soc_mem_t mem = INVALIDm; 5341 soc_field_t fld_limit = INVALIDf; 5342 int granularity = 1; 5343 int from_cos, to_cos, ci; 5344 5345 if (!arg) { 5346 return BCM_E_PARAM; 5347 } 5348 5349 5350 if ((type == bcmCosqControlEgressUCQueueMinLimitBytes) || 5351 (type == bcmCosqControlEgressUCQueueResumeOffsetBytes) || 5352 (type == bcmCosqControlEgressUCQueueSharedLimitBytes)) { 5353 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 5354 BCM_IF_ERROR_RETURN 5355 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 5356 _BCM_TH3_COSQ_INDEX_STYLE_UCAST_QUEUE, 5357 &local_port, &startq, NULL)); 5358 SOC_IF_ERROR_RETURN 5359 (soc_port_pipe_get(unit, local_port, &pipe)); 5360 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 5361 return BCM_E_PARAM; 5362 } 5363 else { 5364 if (cosq == BCM_COS_INVALID) { 5365 from_cos = to_cos = 0; 5366 } else { 5367 from_cos = to_cos = cosq; 5368 } 5369 5370 BCM_IF_ERROR_RETURN 5371 (_bcm_th3_cosq_localport_resolve(unit, gport, &local_port)); 5372 if (local_port < 0) { 5373 return BCM_E_PORT; 5374 } 5375 SOC_IF_ERROR_RETURN(soc_port_pipe_get(unit, local_port, &pipe)); 5376 for (ci = from_cos; ci <= to_cos; ci++) { 5377 BCM_IF_ERROR_RETURN 5378 (_bcm_th3_cosq_index_resolve 5379 (unit, local_port, ci, _BCM_TH3_COSQ_INDEX_STYLE_UCAST_QUEUE, 5380 NULL, &startq, NULL)); 5381 } 5382 } 5383 if (type == bcmCosqControlEgressUCQueueResumeOffsetBytes) { 5384 mem = MMU_THDO_QUEUE_RESUME_OFFSETm; 5385 } else { 5386 mem = MMU_THDO_QUEUE_CONFIGm; 5387 } 5388 } else if ((type == bcmCosqControlEgressMCQueueMinLimitBytes) || 5389 (type == bcmCosqControlEgressMCQueueResumeOffsetBytes) || 5390 (type == bcmCosqControlEgressMCQueueSharedLimitBytes)) { 5391 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 5392 return BCM_E_PARAM; 5393 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 5394 BCM_IF_ERROR_RETURN 5395 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 5396 _BCM_TH3_COSQ_INDEX_STYLE_MCAST_QUEUE, 5397 &local_port, &startq, NULL)); 5398 SOC_IF_ERROR_RETURN(soc_port_pipe_get(unit, local_port, &pipe)); 5399 } 5400 else { 5401 if (cosq == BCM_COS_INVALID) { 5402 from_cos = to_cos = 0; 5403 } else { 5404 from_cos = to_cos = cosq; 5405 } 5406 5407 BCM_IF_ERROR_RETURN 5408 (_bcm_th3_cosq_localport_resolve(unit, gport, &local_port)); 5409 if (local_port < 0) { 5410 return BCM_E_PORT; 5411 } 5412 SOC_IF_ERROR_RETURN(soc_port_pipe_get(unit, local_port, &pipe)); 5413 for (ci = from_cos; ci <= to_cos; ci++) { 5414 BCM_IF_ERROR_RETURN 5415 (_bcm_th3_cosq_index_resolve 5416 (unit, local_port, ci, _BCM_TH3_COSQ_INDEX_STYLE_MCAST_QUEUE, 5417 NULL, &startq, NULL)); 5418 } 5419 } 5420 if (type == bcmCosqControlEgressMCQueueResumeOffsetBytes) { 5421 mem = MMU_THDO_QUEUE_RESUME_OFFSETm; 5422 } else { 5423 mem = MMU_THDO_QUEUE_CONFIGm; 5424 } 5425 } else { 5426 return BCM_E_PARAM; 5427 } 5428 5429 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ALL, startq, entry)); 5430 5431 switch (type) { 5432 case bcmCosqControlEgressUCQueueSharedLimitBytes: 5433 case bcmCosqControlEgressMCQueueSharedLimitBytes: 5434 fld_limit = SHARED_LIMITf; 5435 granularity = 1; 5436 break; 5437 case bcmCosqControlEgressUCQueueMinLimitBytes: 5438 case bcmCosqControlEgressMCQueueMinLimitBytes: 5439 fld_limit = MIN_LIMITf; 5440 granularity = 1; 5441 break; 5442 case bcmCosqControlEgressUCQueueResumeOffsetBytes: 5443 case bcmCosqControlEgressMCQueueResumeOffsetBytes: 5444 fld_limit = RESUME_OFFSETf; 5445 granularity = 8; 5446 break; 5447 default: 5448 return BCM_E_UNAVAIL; 5449 } 5450 5451 BCM_IF_ERROR_RETURN 5452 (soc_mem_read(unit, mem, MEM_BLOCK_ALL, startq, entry)); 5453 *arg = soc_mem_field32_get(unit, mem, entry, fld_limit); 5454 *arg = (*arg) * granularity * _TH3_MMU_BYTES_PER_CELL; 5455 5456 return BCM_E_NONE; 5457 } 5458 5459 /* 5460 * This function is used to get enables 5461 * for Qgroup Min and Shared Limits for a given Egress Unicast Queue 5462 */ 5463 int 5464 _bcm_th3_cosq_qgroup_limit_enables_get(int unit, bcm_gport_t gport, 5465 bcm_cos_t cosq, bcm_cosq_control_t type, 5466 int* arg) 5467 { 5468 bcm_port_t local_port; 5469 int startq=0, pipe=0; 5470 uint32 entry[SOC_MAX_MEM_WORDS]; 5471 soc_mem_t mem = INVALIDm; 5472 soc_field_t field = INVALIDf; 5473 5474 if (!arg) { 5475 return BCM_E_PARAM; 5476 } 5477 5478 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 5479 if (type == bcmCosqControlEgressUCQueueGroupMinEnable) { 5480 BCM_IF_ERROR_RETURN 5481 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 5482 _BCM_TH3_COSQ_INDEX_STYLE_UCAST_QUEUE, 5483 &local_port, &startq, NULL)); 5484 } else { 5485 return BCM_E_PARAM; 5486 } 5487 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 5488 if (type == bcmCosqControlEgressMCQueueGroupMinEnable) { 5489 BCM_IF_ERROR_RETURN 5490 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 5491 _BCM_TH3_COSQ_INDEX_STYLE_MCAST_QUEUE, 5492 &local_port, &startq, NULL)); 5493 } else { 5494 return BCM_E_PARAM; 5495 } 5496 } else { 5497 if (cosq < 0) { 5498 return BCM_E_PARAM; 5499 } 5500 BCM_IF_ERROR_RETURN 5501 (_bcm_th3_cosq_localport_resolve(unit, gport, &local_port)); 5502 if (local_port < 0) { 5503 return BCM_E_PORT; 5504 } 5505 if (type == bcmCosqControlEgressUCQueueGroupMinEnable) { 5506 BCM_IF_ERROR_RETURN 5507 (_bcm_th3_cosq_index_resolve 5508 (unit, local_port, cosq, _BCM_TH3_COSQ_INDEX_STYLE_UCAST_QUEUE, 5509 NULL, &startq, NULL)); 5510 } else { 5511 BCM_IF_ERROR_RETURN 5512 (_bcm_th3_cosq_index_resolve 5513 (unit, local_port, cosq, _BCM_TH3_COSQ_INDEX_STYLE_MCAST_QUEUE, 5514 NULL, &startq, NULL)); 5515 } 5516 } 5517 5518 SOC_IF_ERROR_RETURN(soc_port_pipe_get(unit, local_port, &pipe)); 5519 mem = MMU_THDO_QUEUE_CONFIGm; 5520 if ((type == bcmCosqControlEgressUCQueueGroupMinEnable) || 5521 (type == bcmCosqControlEgressMCQueueGroupMinEnable)) { 5522 field = USE_QGROUP_MINf; 5523 } else { 5524 return BCM_E_PARAM; 5525 } 5526 5527 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ALL, 5528 startq, entry)); 5529 *arg = soc_mem_field32_get(unit, mem, entry, field); 5530 5531 return BCM_E_NONE; 5532 } 5533 5534 /* 5535 * This function is used to set enables 5536 * for Qgroup Min and Shared Limits for a given Egress Unicast Queue 5537 */ 5538 int 5539 _bcm_th3_cosq_qgroup_limit_enables_set(int unit, bcm_gport_t gport, 5540 bcm_cos_t cosq, bcm_cosq_control_t type, 5541 int arg) 5542 { 5543 bcm_port_t local_port; 5544 int startq=0, count=1, lc=0, to_cos=0; 5545 uint32 entry[SOC_MAX_MEM_WORDS], entry2[SOC_MAX_MEM_WORDS]; 5546 soc_mem_t mem = INVALIDm; 5547 soc_mem_t mmu_thdo_per_queue_mem = MMU_THDO_Q_TO_QGRP_MAPD0m; 5548 int enable; 5549 int valid; 5550 soc_field_t field = INVALIDf; 5551 soc_field_t field2 = INVALIDf; 5552 5553 if (arg < 0) { 5554 return BCM_E_PARAM; 5555 } 5556 arg = arg ? 1 : 0; 5557 5558 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 5559 if (type == bcmCosqControlEgressUCQueueGroupMinEnable) { 5560 BCM_IF_ERROR_RETURN 5561 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 5562 _BCM_TH3_COSQ_INDEX_STYLE_UCAST_QUEUE, 5563 &local_port, &startq, NULL)); 5564 } else { 5565 return BCM_E_PARAM; 5566 } 5567 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 5568 if (type == bcmCosqControlEgressMCQueueGroupMinEnable) { 5569 BCM_IF_ERROR_RETURN 5570 (_bcm_th3_cosq_index_resolve(unit, gport, cosq, 5571 _BCM_TH3_COSQ_INDEX_STYLE_MCAST_QUEUE, 5572 &local_port, &startq, NULL)); 5573 } else { 5574 return BCM_E_PARAM; 5575 } 5576 } else { 5577 if (cosq < -1) { 5578 return BCM_E_PARAM; 5579 } 5580 BCM_IF_ERROR_RETURN 5581 (_bcm_th3_cosq_localport_resolve(unit, gport, &local_port)); 5582 if (local_port < 0) { 5583 return BCM_E_PORT; 5584 } 5585 if (type == bcmCosqControlEgressUCQueueGroupMinEnable) { 5586 BCM_IF_ERROR_RETURN 5587 (_bcm_th3_cosq_index_resolve 5588 (unit, local_port, cosq, _BCM_TH3_COSQ_INDEX_STYLE_UCAST_QUEUE, 5589 NULL, &startq, &count)); 5590 } else { 5591 BCM_IF_ERROR_RETURN 5592 (_bcm_th3_cosq_index_resolve 5593 (unit, local_port, cosq, _BCM_TH3_COSQ_INDEX_STYLE_MCAST_QUEUE, 5594 NULL, &startq, &count)); 5595 } 5596 } 5597 5598 mem = MMU_THDO_QUEUE_CONFIGm; 5599 if ((type == bcmCosqControlEgressUCQueueGroupMinEnable) || 5600 (type == bcmCosqControlEgressMCQueueGroupMinEnable)) { 5601 field = USE_QGROUP_MINf; 5602 field2 = QGROUP_VALIDf; 5603 } else { 5604 return BCM_E_PARAM; 5605 } 5606 5607 to_cos = startq + count; 5608 for (lc = startq; lc < to_cos; lc++) { 5609 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ALL, 5610 lc, entry)); 5611 enable = soc_mem_field32_get(unit, mem, entry, field); 5612 if (enable != arg) { 5613 soc_mem_field32_set(unit, mem, entry, field, arg); 5614 BCM_IF_ERROR_RETURN(soc_mem_write(unit, mem, MEM_BLOCK_ALL, 5615 lc, entry)); 5616 } 5617 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mmu_thdo_per_queue_mem, 5618 MEM_BLOCK_ALL, lc, entry2)); 5619 valid = soc_mem_field32_get(unit, mmu_thdo_per_queue_mem, entry2, field2); 5620 if (valid != arg) { 5621 soc_mem_field32_set(unit, mmu_thdo_per_queue_mem, entry2, field2, arg); 5622 BCM_IF_ERROR_RETURN(soc_mem_write(unit, mmu_thdo_per_queue_mem, 5623 MEM_BLOCK_ALL, lc, entry2)); 5624 } 5625 } 5626 5627 /*If qgroup min limit enable is being set, 5628 buffer shared limits will not be recalculated. It is the responsibility 5629 of the user to set the QueueMinLimitBytes to 0 5630 */ 5631 5632 return BCM_E_NONE; 5633 } 5634 5635 /* 5636 * This function is used to get limits 5637 * for Qgroup Min and Shared Limits for a given Egress Unicast Queue 5638 */ 5639 int 5640 _bcm_th3_cosq_qgroup_limit_get(int unit, bcm_gport_t gport, bcm_cos_t cosq, 5641 bcm_cosq_control_t type, int* arg) 5642 { 5643 bcm_port_t local_port; 5644 int pipe; 5645 uint32 entry[SOC_MAX_MEM_WORDS]; 5646 soc_mem_t mem = INVALIDm; 5647 soc_field_t field = INVALIDf; 5648 int granularity; 5649 5650 if (cosq < 0) { 5651 return BCM_E_PARAM; 5652 } 5653 5654 if (BCM_GPORT_IS_SET(gport)) { 5655 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport) || 5656 BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 5657 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport) && 5658 (type != bcmCosqControlEgressUCQueueGroupMinLimitBytes)) { 5659 return BCM_E_PARAM; 5660 } 5661 if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport) && 5662 (type != bcmCosqControlEgressMCQueueGroupMinLimitBytes)) { 5663 return BCM_E_PARAM; 5664 } 5665 } else { /* GPORT is local or modport type */ 5666 if ((type == bcmCosqControlEgressUCQueueGroupMinLimitBytes) && 5667 (cosq >= _bcm_th3_get_num_ucq(unit) )) { 5668 return BCM_E_PARAM; 5669 } 5670 if ((type == bcmCosqControlEgressMCQueueGroupMinLimitBytes) && 5671 (cosq < _bcm_th3_get_num_ucq(unit) )) { 5672 return BCM_E_PARAM; 5673 } 5674 } 5675 } else { /* local port case */ 5676 if ((type == bcmCosqControlEgressUCQueueGroupMinLimitBytes) && 5677 (cosq >= _bcm_th3_get_num_ucq(unit) )) { 5678 return BCM_E_PARAM; 5679 } 5680 if ((type == bcmCosqControlEgressMCQueueGroupMinLimitBytes) && 5681 (cosq < _bcm_th3_get_num_ucq(unit) )) { 5682 return BCM_E_PARAM; 5683 } 5684 } 5685 5686 BCM_IF_ERROR_RETURN 5687 (_bcm_th3_cosq_localport_resolve(unit, gport, &local_port)); 5688 if (local_port < 0) { 5689 return BCM_E_PORT; 5690 } 5691 5692 SOC_IF_ERROR_RETURN(soc_port_pipe_get(unit, local_port, &pipe)); 5693 5694 if ((type == bcmCosqControlEgressUCQueueGroupMinLimitBytes) || 5695 (type == bcmCosqControlEgressMCQueueGroupMinLimitBytes)) { 5696 if (type == bcmCosqControlEgressUCQueueGroupMinLimitBytes) { 5697 mem = MMU_THDO_CONFIG_UC_QGROUP0m; 5698 } 5699 else { 5700 mem = MMU_THDO_CONFIG_MC_QGROUPm; 5701 } 5702 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ALL, 5703 SOC_TH3_MMU_CHIP_PORT(unit, local_port), entry)); 5704 field = MIN_LIMITf; 5705 granularity =1; 5706 } else { 5707 return BCM_E_PARAM; 5708 } 5709 5710 *arg = soc_mem_field32_get(unit, mem, entry, field); 5711 *arg = (*arg) * granularity * _TH3_MMU_BYTES_PER_CELL; 5712 5713 return BCM_E_NONE; 5714 } 5715 5716 /* 5717 * This function is used to set limits 5718 * for Qgroup Min and Shared Limits for a given Egress Unicast Queue 5719 */ 5720 int 5721 _bcm_th3_cosq_qgroup_limit_set(int unit, bcm_gport_t gport, bcm_cos_t cosq, 5722 bcm_cosq_control_t type, int arg) 5723 { 5724 bcm_port_t local_port; 5725 int pipe; 5726 uint32 entry[SOC_MAX_MEM_WORDS]; 5727 soc_mem_t mem = INVALIDm; 5728 soc_field_t field = INVALIDf; 5729 int granularity; 5730 int shd_size[_TH3_ITMS_PER_DEV], cur_val; 5731 int rv, itm; 5732 int delta[_TH3_ITMS_PER_DEV] = {0}; 5733 int max_val; 5734 5735 if (cosq < 0) { 5736 return BCM_E_PARAM; 5737 } 5738 5739 if (BCM_GPORT_IS_SET(gport)) { 5740 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport) || 5741 BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 5742 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport) && 5743 (type != bcmCosqControlEgressUCQueueGroupMinLimitBytes)) { 5744 return BCM_E_PARAM; 5745 } 5746 if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport) && 5747 (type != bcmCosqControlEgressMCQueueGroupMinLimitBytes)) { 5748 return BCM_E_PARAM; 5749 } 5750 } else { /* GPORT is local or modport type */ 5751 if ((type == bcmCosqControlEgressUCQueueGroupMinLimitBytes) && 5752 (cosq >= _bcm_th3_get_num_ucq(unit) )) { 5753 return BCM_E_PARAM; 5754 } 5755 if ((type == bcmCosqControlEgressMCQueueGroupMinLimitBytes) && 5756 (cosq < _bcm_th3_get_num_ucq(unit) )) { 5757 return BCM_E_PARAM; 5758 } 5759 } 5760 } else { /* local port case */ 5761 if ((type == bcmCosqControlEgressUCQueueGroupMinLimitBytes) && 5762 (cosq >= _bcm_th3_get_num_ucq(unit) )) { 5763 return BCM_E_PARAM; 5764 } 5765 if ((type == bcmCosqControlEgressMCQueueGroupMinLimitBytes) && 5766 (cosq < _bcm_th3_get_num_ucq(unit) )) { 5767 return BCM_E_PARAM; 5768 } 5769 } 5770 5771 BCM_IF_ERROR_RETURN 5772 (_bcm_th3_cosq_localport_resolve(unit, gport, &local_port)); 5773 if (local_port < 0) { 5774 return BCM_E_PORT; 5775 } 5776 5777 if ((type == bcmCosqControlEgressUCQueueGroupMinLimitBytes) || 5778 (type == bcmCosqControlEgressMCQueueGroupMinLimitBytes)) { 5779 arg = (arg + _TH3_MMU_BYTES_PER_CELL - 1) / _TH3_MMU_BYTES_PER_CELL; 5780 } 5781 5782 SOC_IF_ERROR_RETURN(soc_port_pipe_get(unit, local_port, &pipe)); 5783 5784 if ((type == bcmCosqControlEgressUCQueueGroupMinLimitBytes) || 5785 (type == bcmCosqControlEgressMCQueueGroupMinLimitBytes)) { 5786 int pool; 5787 if (type == bcmCosqControlEgressUCQueueGroupMinLimitBytes) { 5788 mem = MMU_THDO_CONFIG_UC_QGROUP0m; 5789 } 5790 else { 5791 mem = MMU_THDO_CONFIG_MC_QGROUPm; 5792 } 5793 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ALL, 5794 SOC_TH3_MMU_CHIP_PORT(unit, local_port), entry)); 5795 field = MIN_LIMITf; 5796 granularity =1; 5797 /* Recalculate Shared Values if Min Changed */ 5798 BCM_IF_ERROR_RETURN(_bcm_th3_cosq_egr_pool_get(unit, gport, 5799 cosq, -1, bcmCosqControlEgressPool,&pool)); 5800 sal_memcpy(shd_size, _BCM_TH3_MMU_INFO(unit)->shared_limit, 5801 sizeof(shd_size)); 5802 5803 cur_val = soc_mem_field32_get(unit, mem, entry, field); 5804 /* adjustment delta */ 5805 for (itm = 0; itm < NUM_ITM(unit); itm ++) { 5806 delta[itm] = ((arg / granularity) - cur_val) * granularity; 5807 } 5808 /* shared limits to be increased/decreased */ 5809 for (itm = 0; itm < NUM_ITM(unit); itm ++) { 5810 if (delta[itm] > 0) { 5811 /* no space to decrease shared limit */ 5812 if (delta[itm] > shd_size[itm]) { 5813 return BCM_E_RESOURCE; 5814 } 5815 shd_size[itm] -= delta[itm]; 5816 } 5817 if (delta[itm] < 0) { 5818 shd_size[itm] -= delta[itm]; 5819 } 5820 } 5821 5822 rv = soc_th3_mmu_config_res_limits_update(unit, delta, pool, 1); 5823 5824 if (rv < 0) { 5825 return rv; 5826 } 5827 5828 sal_memcpy(_BCM_TH3_MMU_INFO(unit)->shared_limit,shd_size, 5829 sizeof(shd_size)); 5830 } else { 5831 return BCM_E_PARAM; 5832 } 5833 5834 /* Check for min/max values */ 5835 max_val = (1 << soc_mem_field_length(unit, mem, field)) - 1; 5836 if ((arg < 0) || ((arg/granularity) > max_val)) { 5837 return BCM_E_PARAM; 5838 } else { 5839 soc_mem_field32_set(unit, mem, entry, field, (arg/granularity)); 5840 } 5841 if (type == bcmCosqControlEgressUCQueueGroupMinLimitBytes) { 5842 BCM_IF_ERROR_RETURN(soc_mem_write(unit, mem, MEM_BLOCK_ALL, 5843 SOC_TH3_MMU_CHIP_PORT(unit, local_port), entry)); 5844 } else { 5845 BCM_IF_ERROR_RETURN(soc_mem_write(unit, mem, MEM_BLOCK_ALL, 5846 SOC_TH3_MMU_CHIP_PORT(unit, local_port), entry)); 5847 } 5848 return BCM_E_NONE; 5849 } 5850 5851 /* 5852 * Function: 5853 * bcm_th3_cosq_gport_traverse 5854 * Purpose: 5855 * Walks through the valid COSQ GPORTs and calls 5856 * the user supplied callback function for each entry. 5857 * Parameters: 5858 * unit - (IN) unit number 5859 * trav_fn - (IN) Callback function. 5860 * user_data - (IN) User data to be passed to callback function 5861 * Returns: 5862 * BCM_E_NONE - Success. 5863 * BCM_E_XXX 5864 */ 5865 int 5866 bcm_th3_cosq_gport_traverse(int unit, bcm_cosq_gport_traverse_cb cb, 5867 void *user_data) 5868 { 5869 _bcm_th3_cosq_port_info_t *port_info = NULL; 5870 _bcm_th3_cosq_cpu_port_info_t *cpu_port_info = NULL; 5871 bcm_module_t my_modid, modid_out; 5872 bcm_port_t port, port_out, local_port; 5873 bcm_gport_t gport; 5874 int id, rv = SOC_E_NONE; 5875 5876 if (_bcm_th3_cosq_port_info[unit] == NULL) { 5877 return BCM_E_INIT; 5878 } 5879 if (_bcm_th3_cosq_cpu_port_info[unit] == NULL) { 5880 return BCM_E_INIT; 5881 } 5882 5883 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &my_modid)); 5884 PBMP_ALL_ITER(unit, port) { 5885 BCM_IF_ERROR_RETURN 5886 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET, 5887 my_modid, port, &modid_out, &port_out)); 5888 BCM_GPORT_MODPORT_SET(gport, modid_out, port_out); 5889 5890 BCM_IF_ERROR_RETURN 5891 (_bcm_th3_cosq_localport_resolve(unit, port, &local_port)); 5892 5893 if (IS_CPU_PORT(unit, local_port)) { 5894 cpu_port_info = &_bcm_th3_cosq_cpu_port_info[unit][local_port]; 5895 } else { 5896 port_info = &_bcm_th3_cosq_port_info[unit][local_port]; 5897 } 5898 if (!IS_CPU_PORT(unit, local_port)) { 5899 for (id = 0; id < _bcm_th3_get_num_ucq(unit); id++) { 5900 if (port_info->ucast[id].numq == 0) { 5901 continue; 5902 } 5903 rv = cb(unit, gport, port_info->ucast[id].numq, 5904 BCM_COSQ_GPORT_UCAST_QUEUE_GROUP, 5905 port_info->ucast[id].gport, user_data); 5906 #ifdef BCM_CB_ABORT_ON_ERR 5907 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 5908 return rv; 5909 } 5910 #else 5911 /* 5912 * If CB_ABORT_ON_ERR is not defined don't return error 5913 * and continue. 5914 */ 5915 rv = BCM_E_NONE; 5916 #endif 5917 } 5918 } 5919 if (IS_CPU_PORT(unit, local_port)) { 5920 for (id = 0; id < _BCM_TH3_NUM_CPU_MCAST_QUEUE; id++) { 5921 if (cpu_port_info->mcast[id].numq == 0) { 5922 continue; 5923 } 5924 rv = cb(unit, gport, cpu_port_info->mcast[id].numq, 5925 BCM_COSQ_GPORT_MCAST_QUEUE_GROUP, 5926 cpu_port_info->mcast[id].gport, user_data); 5927 #ifdef BCM_CB_ABORT_ON_ERR 5928 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 5929 return rv; 5930 } 5931 #else 5932 /* 5933 * If CB_ABORT_ON_ERR is not defined don't return error 5934 * and continue. 5935 */ 5936 rv = BCM_E_NONE; 5937 #endif 5938 } 5939 } else { 5940 for (id = 0; id < _bcm_th3_get_num_mcq(unit); id++) { 5941 if (port_info->mcast[id].numq == 0) { 5942 continue; 5943 } 5944 rv = cb(unit, gport, port_info->mcast[id].numq, 5945 BCM_COSQ_GPORT_MCAST_QUEUE_GROUP, 5946 port_info->mcast[id].gport, user_data); 5947 #ifdef BCM_CB_ABORT_ON_ERR 5948 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 5949 return rv; 5950 } 5951 #else 5952 /* 5953 * If CB_ABORT_ON_ERR is not defined don't return error 5954 * and continue. 5955 */ 5956 rv = BCM_E_NONE; 5957 #endif 5958 } 5959 } 5960 for (id = 0; id < _BCM_TH3_NUM_SCHEDULER_PER_PORT; id++) { 5961 if (IS_CPU_PORT(unit, local_port)) { 5962 if (cpu_port_info->sched[id].numq == 0) { 5963 continue; 5964 } 5965 rv = cb(unit, gport, cpu_port_info->sched[id].numq, 5966 BCM_COSQ_GPORT_SCHEDULER, 5967 cpu_port_info->sched[id].gport, user_data); 5968 } else { 5969 if (port_info->sched[id].numq == 0 || 5970 port_info->sched[id].in_use == 0) { 5971 continue; 5972 } 5973 rv = cb(unit, gport, port_info->sched[id].numq, 5974 BCM_COSQ_GPORT_SCHEDULER, 5975 port_info->sched[id].gport, user_data); 5976 } 5977 #ifdef BCM_CB_ABORT_ON_ERR 5978 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 5979 return rv; 5980 } 5981 #else 5982 /* 5983 * If CB_ABORT_ON_ERR is not defined don't return error 5984 * and continue. 5985 */ 5986 rv = BCM_E_NONE; 5987 #endif 5988 } 5989 } 5990 return rv; 5991 } 5992 5993 /* 5994 * Function: 5995 * bcm_th3_cosq_gport_attach_get 5996 * Purpose: 5997 * Get attached status of a scheduler port 5998 * Parameters: 5999 * unit - (IN) unit number 6000 * sched_port - (IN) scheduler GPORT identifier 6001 * input_port - (OUT) GPORT to attach to 6002 * cosq - (OUT) COS queue to attached to 6003 * Returns: 6004 * BCM_E_XXX 6005 * Notes: 6006 */ 6007 int 6008 bcm_th3_cosq_gport_attach_get(int unit, bcm_gport_t sched_gport, 6009 bcm_gport_t *input_gport, bcm_cos_queue_t *cosq) 6010 { 6011 _bcm_th3_cosq_node_t *node = NULL; 6012 int cpu_mc_base = 0; 6013 bcm_port_t local_port = -1; 6014 soc_info_t *si = &SOC_INFO(unit); 6015 6016 if (!(BCM_GPORT_IS_SET(sched_gport) || 6017 BCM_GPORT_IS_SCHEDULER(sched_gport) || 6018 BCM_GPORT_IS_UCAST_QUEUE_GROUP(sched_gport) || 6019 BCM_GPORT_IS_MCAST_QUEUE_GROUP(sched_gport))) { 6020 return BCM_E_PARAM; 6021 } 6022 6023 BCM_IF_ERROR_RETURN 6024 (_bcm_th3_cosq_node_get(unit, sched_gport, NULL, &local_port, NULL, 6025 &node)); 6026 if (node == NULL) { 6027 return BCM_E_PARAM; 6028 } 6029 6030 if (local_port < 0) { 6031 return BCM_E_PARAM; 6032 } 6033 6034 if (BCM_GPORT_IS_SCHEDULER(sched_gport)) { 6035 if (IS_CPU_PORT(unit, local_port)) { 6036 *cosq = (node->hw_index - cpu_mc_base) % _BCM_TH3_NUM_SCHEDULER_PER_PORT; 6037 } else { 6038 *cosq = node->cos % _BCM_TH3_NUM_SCHEDULER_PER_PORT; 6039 } 6040 } else if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(sched_gport)) { 6041 *cosq = node->cos % _BCM_TH3_MAX_QUEUE_PER_PORT; 6042 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(sched_gport)) { 6043 if (IS_CPU_PORT(unit, local_port)) { 6044 cpu_mc_base = si->port_cosq_base[CMIC_PORT(unit)]; 6045 *cosq = (node->hw_index - cpu_mc_base) % _BCM_TH3_NUM_CPU_MCAST_QUEUE; 6046 } else { 6047 *cosq = node->cos % _BCM_TH3_MAX_QUEUE_PER_PORT; 6048 } 6049 } else { 6050 return BCM_E_PARAM; 6051 } 6052 *input_gport = node->parent_gport; 6053 6054 return BCM_E_NONE; 6055 } 6056 6057 6058 /* 6059 * Function: 6060 * _bcm_th3_cosq_gport_cpu_tree_create 6061 * Purpose: 6062 * During cosq init create the default cosq gport tree for CPU. 6063 * Schedualar (L0) nodes are created and attach to physical ports. 6064 * UC and MC queues are added and attached to each L0 nodes. 6065 * Parameters: 6066 * unit - (IN) unit number. 6067 * port - (IN) port number 6068 * Returns: 6069 * BCM_E_XXX 6070 */ 6071 int 6072 _bcm_th3_cosq_gport_cpu_tree_create(int unit, bcm_port_t port) 6073 { 6074 bcm_gport_t cpu_mc_gport[_BCM_TH3_NUM_CPU_MCAST_QUEUE]; 6075 int id, pci_cmc = SOC_PCI_CMC(unit); 6076 int ch_l0_map; 6077 bcm_gport_t sched_gport[_BCM_TH3_NUM_SCHEDULER_PER_PORT]; 6078 int numq; 6079 int num_queues_uc0 = soc_property_get(unit, "num_queues_uc0", 0); 6080 int num_queues_uc1 = soc_property_get(unit, "num_queues_uc1", 0); 6081 6082 if (!IS_CPU_PORT(unit, port)) { 6083 return BCM_E_PARAM; 6084 } 6085 /* CMIC requires all 48 queues to be set and for the respective CMC */ 6086 if ((NUM_CPU_ARM_COSQ(unit, pci_cmc) + num_queues_uc0 + num_queues_uc1) != 6087 SOC_TH3_NUM_CPU_QUEUES) { 6088 return BCM_E_PARAM; 6089 } 6090 6091 6092 numq = 48; 6093 /* Adding L0 (schedular) nodes and attaching them to cpu port */ 6094 for (id = 0; id < _BCM_TH3_NUM_SCHEDULER_PER_PORT; id++) { 6095 BCM_IF_ERROR_RETURN 6096 (bcm_th3_cosq_gport_add(unit, port, numq, BCM_COSQ_GPORT_SCHEDULER, 6097 &sched_gport[id])); 6098 BCM_IF_ERROR_RETURN 6099 (bcm_th3_cosq_gport_attach(unit, sched_gport[id], port, id)); 6100 LOG_INFO(BSL_LS_BCM_COSQ, 6101 (BSL_META_U(unit, 6102 "sched_gport[%d]=0x%x\n"), 6103 id, sched_gport[id])); 6104 } 6105 /* Add MC queues and attach them to Schedular nodes. 6106 * L0.0 node - PCI host 6107 * L0.7 node - uc0 6108 * L0.8 node - uc1 6109 */ 6110 6111 /* CMICX supports only 2 CMCs. 6112 * CMC0 connected to PCI. 6113 * CMC1 is connected to other arm cores. 6114 */ 6115 6116 for (id = 0; id < _BCM_TH3_NUM_CPU_MCAST_QUEUE; id++) { 6117 ch_l0_map = (id < NUM_CPU_ARM_COSQ(unit, pci_cmc)) ? pci_cmc : 6118 (id < (NUM_CPU_ARM_COSQ(unit, pci_cmc) + 6119 (num_queues_uc0))) ? 7 : 8; 6120 BCM_IF_ERROR_RETURN 6121 (bcm_th3_cosq_gport_add(unit, 0, 1, 6122 BCM_COSQ_GPORT_MCAST_QUEUE_GROUP, 6123 &cpu_mc_gport[id])); 6124 BCM_IF_ERROR_RETURN 6125 (bcm_th3_cosq_gport_attach(unit, cpu_mc_gport[id], 6126 sched_gport[ch_l0_map], id)); 6127 } 6128 6129 6130 return SOC_E_NONE; 6131 } 6132 6133 6134 /* 6135 * Function: 6136 * _bcm_th3_cosq_gport_tree_create 6137 * Purpose: 6138 * During cosq init create the default cosq gport tree. 6139 * Schedualar (L0) nodes are created and attach to physical ports. 6140 * UC and MC queues are added and attached to each L0 nodes. 6141 * Parameters: 6142 * unit - (IN) unit number. 6143 * port - (IN) port number 6144 * Returns: 6145 * BCM_E_XXX 6146 */ 6147 int 6148 _bcm_th3_cosq_gport_tree_create(int unit, bcm_port_t port) 6149 { 6150 int id; 6151 6152 if (IS_CPU_PORT(unit, port)) { 6153 _bcm_th3_cosq_gport_cpu_tree_create(unit, port); 6154 } else { 6155 /* Adding L0 (schedular) nodes and attaching them to front panel and cpu port */ 6156 for (id = 0; id < _BCM_TH3_NUM_SCHEDULER_PER_PORT; id++) { 6157 BCM_IF_ERROR_RETURN 6158 (_bcm_th3_cosq_gport_add_attach(unit, port, id, BCM_COSQ_GPORT_SCHEDULER)); 6159 } 6160 6161 /* Adding UC/MC queues and attaching them to Schedular nodes */ 6162 for (id = 0; id < _BCM_TH3_MAX_NUM_QUEUE_PER_PORT; id++) { 6163 BCM_IF_ERROR_RETURN 6164 (_bcm_th3_cosq_gport_add_attach(unit, port, id, 0)); 6165 } 6166 } 6167 6168 return SOC_E_NONE; 6169 } 6170 6171 /* 6172 * Function: 6173 * bcm_th3_cosq_sched_weight_max_get 6174 * Purpose: 6175 * Retrieve maximum weights for given COS policy 6176 * Parameters: 6177 * unit - (IN) unit number 6178 * mode - (IN) Scheduling mode (BCM_COSQ_xxx) 6179 * weight_max - (OUT) Maximum weight for COS queue. 6180 * Returns: 6181 * BCM_E_XXX 6182 */ 6183 int 6184 bcm_th3_cosq_sched_weight_max_get(int unit, int mode, int *weight_max) 6185 { 6186 switch (mode) { 6187 case BCM_COSQ_STRICT: 6188 *weight_max = BCM_COSQ_WEIGHT_STRICT; 6189 break; 6190 case BCM_COSQ_ROUND_ROBIN: 6191 case BCM_COSQ_WEIGHTED_ROUND_ROBIN: 6192 case BCM_COSQ_DEFICIT_ROUND_ROBIN: 6193 /* In TH the maximum weight will be 127 */ 6194 *weight_max = 6195 (1 << soc_mem_field_length(unit, MMU_QSCH_L0_WEIGHT_MEMm, 6196 WEIGHTf)) - 1; 6197 break; 6198 default: 6199 return BCM_E_PARAM; 6200 } 6201 6202 return BCM_E_NONE; 6203 } 6204 6205 6206 /* 6207 * Function: 6208 * bcm_th3_cosq_gport_get 6209 * Purpose: 6210 * Get a cosq gport structure 6211 * Parameters: 6212 * unit - (IN) unit number 6213 * gport - (IN) GPORT identifier 6214 * port - (OUT) port number 6215 * numq - (OUT) number of COS queues 6216 * flags - (OUT) flags (BCM_COSQ_GPORT_XXX) 6217 * Returns: 6218 * BCM_E_XXX 6219 */ 6220 int 6221 bcm_th3_cosq_gport_get(int unit, bcm_gport_t gport, bcm_gport_t *port, 6222 int *numq, uint32 *flags) 6223 { 6224 _bcm_th3_cosq_node_t *node; 6225 bcm_port_t local_port; 6226 bcm_module_t modid; 6227 _bcm_gport_dest_t dest; 6228 6229 if (port == NULL || numq == NULL || flags == NULL) { 6230 return BCM_E_PARAM; 6231 } 6232 6233 if ((BCM_GPORT_IS_SCHEDULER(gport)) || 6234 BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport) || 6235 BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport) || 6236 BCM_GPORT_IS_UCAST_SUBSCRIBER_QUEUE_GROUP(gport)) { 6237 BCM_IF_ERROR_RETURN 6238 (_bcm_th3_cosq_node_get(unit, gport, NULL, &local_port, 6239 NULL, &node)); 6240 6241 *numq = node->numq; 6242 6243 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 6244 *flags = BCM_COSQ_GPORT_UCAST_QUEUE_GROUP; 6245 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 6246 *flags = BCM_COSQ_GPORT_MCAST_QUEUE_GROUP; 6247 } else if (BCM_GPORT_IS_SCHEDULER(gport)) { 6248 *flags = BCM_COSQ_GPORT_SCHEDULER; 6249 } else { 6250 *flags = 0; 6251 } 6252 } else { 6253 BCM_IF_ERROR_RETURN 6254 (_bcm_th3_cosq_localport_resolve(unit, gport, &local_port)); 6255 *flags = 0; 6256 *numq = _BCM_TH3_NUM_SCHEDULER_PER_PORT; 6257 } 6258 6259 if (SOC_USE_GPORT(unit)) { 6260 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &modid)); 6261 dest.gport_type = _SHR_GPORT_TYPE_MODPORT; 6262 dest.modid = modid; 6263 dest.port = local_port; 6264 BCM_IF_ERROR_RETURN(_bcm_esw_gport_construct(unit, &dest, port)); 6265 } else { 6266 *port = local_port; 6267 } 6268 6269 LOG_INFO(BSL_LS_BCM_COSQ, 6270 (BSL_META_U(unit, 6271 "port=0x%x numq=%d flags=0x%x\n"), 6272 *port, *numq, *flags)); 6273 6274 return BCM_E_NONE; 6275 } 6276 6277 /* 6278 * Function: 6279 * bcm_tomahawk3_cosq_schedq_mapping_set 6280 * Purpose: 6281 * Get a cosq gport structure 6282 * Parameters: 6283 * unit - (IN) unit number 6284 * profile_index - (IN) Profile index 6285 * size - (OUT) Array size 6286 * cosq_mapping_arr - (OUT) Cosq mapping 6287 * Returns: 6288 * BCM_E_XXX 6289 */ 6290 int 6291 bcm_tomahawk3_cosq_schedq_mapping_set(int unit, int profile_index, 6292 int size, bcm_cosq_mapping_t *cosq_mapping_arr) 6293 { 6294 _soc_mmu_cfg_scheduler_profile_t *sched_profile; 6295 int cosq_idx, cos; 6296 int L0[_BCM_TH3_COS_MAX]; 6297 int schedq[_BCM_TH3_COS_MAX]; 6298 int mmuq[_BCM_TH3_COS_MAX]; 6299 int cos_list[_BCM_TH3_COS_MAX]; 6300 int strict_priority[_BCM_TH3_COS_MAX]; 6301 int fc_is_uc_only[_BCM_TH3_COS_MAX]; 6302 bcm_port_t port; 6303 int rv = BCM_E_NONE; 6304 6305 if (profile_index < 0 || profile_index >= SOC_TH3_MAX_NUM_SCHED_PROFILE) { 6306 return BCM_E_PARAM; 6307 } 6308 if (cosq_mapping_arr == NULL) { 6309 return BCM_E_PARAM; 6310 } 6311 if (size < 0 || size > _BCM_TH3_COS_MAX) { 6312 return BCM_E_PARAM; 6313 } 6314 6315 sched_profile = soc_mmu_cfg_scheduler_profile_alloc(unit); 6316 6317 for (cosq_idx = 0; cosq_idx < _BCM_TH3_COS_MAX; cosq_idx++) { 6318 sched_profile[profile_index].num_unicast_queue[cosq_idx] = 0; 6319 sched_profile[profile_index].num_multicast_queue[cosq_idx] = 0; 6320 sched_profile[profile_index].strict_priority[cosq_idx] = 0; 6321 sched_profile[profile_index].flow_control_only_unicast[cosq_idx] = 0; 6322 } 6323 6324 for (cosq_idx = 0; cosq_idx < size; cosq_idx++) { 6325 cos = cosq_mapping_arr[cosq_idx].cosq; 6326 sched_profile[profile_index].num_unicast_queue[cos] = cosq_mapping_arr[cosq_idx].num_ucq; 6327 sched_profile[profile_index].num_multicast_queue[cos] = cosq_mapping_arr[cosq_idx].num_mcq; 6328 sched_profile[profile_index].strict_priority[cos] = cosq_mapping_arr[cosq_idx].strict_priority; 6329 sched_profile[profile_index].flow_control_only_unicast[cos] = cosq_mapping_arr[cosq_idx].fc_is_uc_only; 6330 sched_profile[profile_index].valid = 1; 6331 } 6332 rv = _soc_mmu_tomahawk3_scheduler_profile_config_check(unit, 6333 profile_index, sched_profile); 6334 if (rv != BCM_E_NONE) { 6335 goto exit; 6336 } 6337 6338 rv = _soc_scheduler_profile_mapping_setup(unit, 6339 sched_profile, profile_index, L0, schedq, mmuq, cos_list, 6340 strict_priority, fc_is_uc_only); 6341 if (rv != BCM_E_NONE) { 6342 goto exit; 6343 } 6344 6345 /*initilization of L0.i->schedq.i->mmuq.i*/ 6346 LOG_INFO(BSL_LS_BCM_COSQ, 6347 (BSL_META_U(unit, "Profile %d cos %d L0 %d schedq %d mmuq %d cos_list %d\n"), 6348 profile_index, cosq_idx, L0[cosq_idx], schedq[cosq_idx], mmuq[cosq_idx], cos_list[cosq_idx])); 6349 rv = soc_tomahawk3_sched_update_init(unit, profile_index, L0, schedq, mmuq, cos_list, strict_priority, fc_is_uc_only); 6350 if (rv != BCM_E_NONE) { 6351 goto exit; 6352 } 6353 6354 _BCM_TH3_MMU_INFO(unit)->gport_tree_created = FALSE; 6355 PBMP_ALL_ITER(unit, port) { 6356 if (IS_LB_PORT(unit, port)) { 6357 continue; 6358 } 6359 rv = _bcm_th3_cosq_gport_tree_create(unit, port); 6360 if (rv != BCM_E_NONE) { 6361 goto exit; 6362 } 6363 } 6364 _BCM_TH3_MMU_INFO(unit)->gport_tree_created = TRUE; 6365 6366 exit: 6367 soc_mmu_cfg_scheduler_profile_free(unit, sched_profile); 6368 6369 return rv; 6370 } 6371 6372 6373 /* 6374 * Function: 6375 * bcm_tomahawk3_cosq_schedq_mapping_get 6376 * Purpose: 6377 * Get a cosq gport structure 6378 * Parameters: 6379 * unit - (IN) unit number 6380 * profile_index - (IN) Profile index 6381 * size - (OUT) Array size 6382 * cosq_mapping_arr - (OUT) Cosq mapping 6383 * Returns: 6384 * BCM_E_XXX 6385 */ 6386 int 6387 bcm_tomahawk3_cosq_schedq_mapping_get(int unit, int profile_index, 6388 int array_max, bcm_cosq_mapping_t *cosq_mapping_arr, int *size) 6389 { 6390 int cosq_idx, qidx; 6391 6392 if (profile_index < 0 || profile_index >= SOC_TH3_MAX_NUM_SCHED_PROFILE) { 6393 return BCM_E_PARAM; 6394 } 6395 if (array_max < 0 || array_max > _BCM_TH3_COS_MAX) { 6396 return BCM_E_PARAM; 6397 } 6398 if (cosq_mapping_arr == NULL) { 6399 return BCM_E_PARAM; 6400 } 6401 for (cosq_idx = 0; cosq_idx < array_max; cosq_idx++) { 6402 cosq_mapping_arr[cosq_idx].cosq = cosq_idx; 6403 cosq_mapping_arr[cosq_idx].num_ucq = -1; 6404 cosq_mapping_arr[cosq_idx].num_mcq = -1; 6405 cosq_mapping_arr[cosq_idx].strict_priority = 0; 6406 cosq_mapping_arr[cosq_idx].fc_is_uc_only = 0; 6407 } 6408 6409 cosq_idx = 0; 6410 for (qidx = 0; qidx < _BCM_TH3_MAX_NUM_QUEUE_PER_PORT; qidx++) { 6411 if (cosq_idx >= array_max) { 6412 break; 6413 } 6414 if (th3_sched_profile_info[unit][profile_index][qidx].cos == -1) { 6415 continue; 6416 } 6417 cosq_mapping_arr[cosq_idx].cosq = th3_sched_profile_info[unit][profile_index][qidx].cos; 6418 if (th3_sched_profile_info[unit][profile_index][qidx].mmuq[0] != -1) { 6419 cosq_mapping_arr[cosq_idx].num_ucq = 0; 6420 cosq_mapping_arr[cosq_idx].num_mcq = 0; 6421 if (th3_sched_profile_info[unit][profile_index][qidx].mmuq[0] < 6422 _bcm_th3_get_num_ucq(unit)) { 6423 cosq_mapping_arr[cosq_idx].num_ucq++; 6424 } else { 6425 cosq_mapping_arr[cosq_idx].num_mcq++; 6426 } 6427 } 6428 if (th3_sched_profile_info[unit][profile_index][qidx].mmuq[1] != -1) { 6429 if (th3_sched_profile_info[unit][profile_index][qidx].mmuq[1] < 6430 _bcm_th3_get_num_ucq(unit)) { 6431 cosq_mapping_arr[cosq_idx].num_ucq++; 6432 } else { 6433 cosq_mapping_arr[cosq_idx].num_mcq++; 6434 } 6435 } 6436 cosq_mapping_arr[cosq_idx].strict_priority = 6437 th3_sched_profile_info[unit][profile_index][qidx].strict_priority; 6438 cosq_mapping_arr[cosq_idx].fc_is_uc_only = 6439 th3_sched_profile_info[unit][profile_index][qidx].fc_is_uc_only; 6440 cosq_idx++; 6441 } 6442 6443 *size = cosq_idx; 6444 6445 return BCM_E_NONE; 6446 } 6447 6448 /* Registers accessed for IDB APIs */ 6449 static const soc_mem_t 6450 obm_pri_map_mem[_TH3_PBLKS_PER_PIPE][_TH3_PORTS_PER_PBLK] = { 6451 {IDB_OBM0_PRI_MAP_PORT0m, IDB_OBM0_PRI_MAP_PORT1m, 6452 IDB_OBM0_PRI_MAP_PORT2m, IDB_OBM0_PRI_MAP_PORT3m, 6453 IDB_OBM0_PRI_MAP_PORT4m, IDB_OBM0_PRI_MAP_PORT5m, 6454 IDB_OBM0_PRI_MAP_PORT6m, IDB_OBM0_PRI_MAP_PORT7m}, 6455 {IDB_OBM1_PRI_MAP_PORT0m, IDB_OBM1_PRI_MAP_PORT1m, 6456 IDB_OBM1_PRI_MAP_PORT2m, IDB_OBM1_PRI_MAP_PORT3m, 6457 IDB_OBM1_PRI_MAP_PORT4m, IDB_OBM1_PRI_MAP_PORT5m, 6458 IDB_OBM1_PRI_MAP_PORT6m, IDB_OBM1_PRI_MAP_PORT7m}, 6459 {IDB_OBM2_PRI_MAP_PORT0m, IDB_OBM2_PRI_MAP_PORT1m, 6460 IDB_OBM2_PRI_MAP_PORT2m, IDB_OBM2_PRI_MAP_PORT3m, 6461 IDB_OBM2_PRI_MAP_PORT4m, IDB_OBM2_PRI_MAP_PORT5m, 6462 IDB_OBM2_PRI_MAP_PORT6m, IDB_OBM2_PRI_MAP_PORT7m}, 6463 {IDB_OBM3_PRI_MAP_PORT0m, IDB_OBM3_PRI_MAP_PORT1m, 6464 IDB_OBM3_PRI_MAP_PORT2m, IDB_OBM3_PRI_MAP_PORT3m, 6465 IDB_OBM3_PRI_MAP_PORT4m, IDB_OBM3_PRI_MAP_PORT5m, 6466 IDB_OBM3_PRI_MAP_PORT6m, IDB_OBM3_PRI_MAP_PORT7m}, 6467 }; 6468 static const soc_mem_t 6469 obm_dscp_map_mem[_TH3_PBLKS_PER_PIPE][_TH3_PORTS_PER_PBLK] = { 6470 {IDB_OBM0_DSCP_MAP_PORT0m, IDB_OBM0_DSCP_MAP_PORT1m, 6471 IDB_OBM0_DSCP_MAP_PORT2m, IDB_OBM0_DSCP_MAP_PORT3m, 6472 IDB_OBM0_DSCP_MAP_PORT4m, IDB_OBM0_DSCP_MAP_PORT5m, 6473 IDB_OBM0_DSCP_MAP_PORT6m, IDB_OBM0_DSCP_MAP_PORT7m}, 6474 {IDB_OBM1_DSCP_MAP_PORT0m, IDB_OBM1_DSCP_MAP_PORT1m, 6475 IDB_OBM1_DSCP_MAP_PORT2m, IDB_OBM1_DSCP_MAP_PORT3m, 6476 IDB_OBM1_DSCP_MAP_PORT4m, IDB_OBM1_DSCP_MAP_PORT5m, 6477 IDB_OBM1_DSCP_MAP_PORT6m, IDB_OBM1_DSCP_MAP_PORT7m}, 6478 {IDB_OBM2_DSCP_MAP_PORT0m, IDB_OBM2_DSCP_MAP_PORT1m, 6479 IDB_OBM2_DSCP_MAP_PORT2m, IDB_OBM2_DSCP_MAP_PORT3m, 6480 IDB_OBM2_DSCP_MAP_PORT4m, IDB_OBM2_DSCP_MAP_PORT5m, 6481 IDB_OBM2_DSCP_MAP_PORT6m, IDB_OBM2_DSCP_MAP_PORT7m}, 6482 {IDB_OBM3_DSCP_MAP_PORT0m, IDB_OBM3_DSCP_MAP_PORT1m, 6483 IDB_OBM3_DSCP_MAP_PORT2m, IDB_OBM3_DSCP_MAP_PORT3m, 6484 IDB_OBM3_DSCP_MAP_PORT4m, IDB_OBM3_DSCP_MAP_PORT5m, 6485 IDB_OBM3_DSCP_MAP_PORT6m, IDB_OBM3_DSCP_MAP_PORT7m}, 6486 }; 6487 static const soc_field_t obm_ob_pri_fields[8] = { 6488 OFFSET0_OB_PRIORITYf, OFFSET1_OB_PRIORITYf, OFFSET2_OB_PRIORITYf, 6489 OFFSET3_OB_PRIORITYf, OFFSET4_OB_PRIORITYf, OFFSET5_OB_PRIORITYf, 6490 OFFSET6_OB_PRIORITYf, OFFSET7_OB_PRIORITYf 6491 }; 6492 6493 static const soc_reg_t obm_port_config_regs[_TH3_PBLKS_PER_PIPE] = { 6494 IDB_OBM0_PORT_CONFIGr, IDB_OBM1_PORT_CONFIGr, 6495 IDB_OBM2_PORT_CONFIGr, IDB_OBM3_PORT_CONFIGr 6496 }; 6497 6498 /* New APIs for IDB */ 6499 STATIC int 6500 _bcm_th3_enable_dscp_ob_pri_mapping (int unit, soc_reg_t reg, int index, int 6501 inst) { 6502 6503 uint32 rval = 0; 6504 BCM_IF_ERROR_RETURN 6505 (soc_reg32_get(unit, reg, inst, index, &rval)); 6506 soc_reg_field_set(unit, reg, &rval, TRUST_DSCPf, 1); 6507 BCM_IF_ERROR_RETURN( 6508 soc_reg32_set(unit, reg, inst, index, rval)); 6509 6510 6511 return BCM_E_NONE; 6512 } 6513 6514 /* 6515 * Function: 6516 * bcm_tomahawk3_obm_port_pri_traffic_class_mapping_set 6517 * Purpose: 6518 * Determine which COS queue a given priority currently maps to. 6519 * Parameters: 6520 * unit - (IN) unit number 6521 * port - (IN) port number 6522 * priority_type - (IN) Lookup priority type 6523 * obm_tc - (IN) OBM traffic class to be mapped 6524 * Returns: 6525 * BCM_E_XXX 6526 */ 6527 int 6528 bcm_tomahawk3_obm_port_pri_traffic_class_mapping_set(int unit, bcm_port_t port, 6529 bcm_obm_lookup_priority_type_t piority_type, int priority, 6530 bcm_obm_traffic_class_t obm_tc) 6531 { 6532 int phy_port, pm_num, pipe, subp; 6533 soc_mem_t mem = INVALIDm; 6534 soc_reg_t reg = INVALIDr; 6535 soc_field_t field = INVALIDf, reg_field = INVALIDf; 6536 soc_info_t *si = &SOC_INFO(unit); 6537 int index, field_val, reg_field_val = 0; 6538 uint32 rval; 6539 uint32 entry[SOC_MAX_MEM_WORDS]; 6540 6541 if (!SOC_PORT_VALID(unit, port)) { 6542 return BCM_E_PORT; 6543 } 6544 if (priority < 0 || priority >= 8) { 6545 return BCM_E_PARAM; 6546 } 6547 6548 switch(obm_tc) { 6549 case bcmObmClassLossyLow: 6550 field_val = 0; 6551 break; 6552 case bcmObmClassLossyHigh: 6553 field_val = 1; 6554 break; 6555 case bcmObmClassLossless0: 6556 field_val = 2; 6557 break; 6558 case bcmObmClassLossless1: 6559 field_val = 3; 6560 break; 6561 default: 6562 return BCM_E_PARAM; 6563 } 6564 6565 phy_port = si->port_l2p_mapping[port]; 6566 pipe = si->port_pipe[port]; 6567 pm_num = soc_tomahawk3_get_pipe_pm_from_phy_port(phy_port); 6568 subp = soc_tomahawk3_get_subp_from_phy_port(phy_port); 6569 6570 switch(piority_type) { 6571 case bcmObmPriorityTypeVLAN: 6572 mem = SOC_MEM_UNIQUE_ACC_PIPE(unit, obm_pri_map_mem[pm_num][subp], 6573 pipe); 6574 field = obm_ob_pri_fields[priority]; 6575 index = 0; 6576 break; 6577 case bcmObmPriorityTypeDSCP: 6578 mem = SOC_MEM_UNIQUE_ACC_PIPE(unit, obm_dscp_map_mem[pm_num][subp], 6579 pipe); 6580 field = obm_ob_pri_fields[priority]; 6581 index = 0; 6582 BCM_IF_ERROR_RETURN( 6583 _bcm_th3_enable_dscp_ob_pri_mapping(unit, 6584 obm_port_config_regs[pm_num], subp, pipe)); 6585 break; 6586 case bcmObmPriorityTypeUntagged: 6587 reg = obm_port_config_regs[pm_num]; 6588 reg_field = PORT_PRIf; 6589 index = subp; 6590 reg_field_val = priority; 6591 mem = SOC_MEM_UNIQUE_ACC_PIPE(unit, obm_pri_map_mem[pm_num][subp], 6592 pipe); 6593 field = obm_ob_pri_fields[priority]; 6594 break; 6595 default: 6596 return BCM_E_PARAM; 6597 } 6598 6599 if (mem!= INVALIDm && field != INVALIDf) { 6600 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ALL, 6601 index, &entry)); 6602 soc_mem_field32_set(unit, mem, &entry, field , field_val); 6603 BCM_IF_ERROR_RETURN 6604 (soc_mem_write(unit, mem, MEM_BLOCK_ALL, index, &entry)); 6605 } 6606 if (reg != INVALIDr && reg_field != INVALIDf) { 6607 rval = 0; 6608 BCM_IF_ERROR_RETURN 6609 (soc_reg32_get(unit, reg, pipe, index, &rval)); 6610 soc_reg_field_set(unit, reg, &rval, reg_field, reg_field_val); 6611 BCM_IF_ERROR_RETURN( 6612 soc_reg32_set(unit, reg, pipe, index, rval)); 6613 } 6614 return BCM_E_NONE; 6615 } 6616 6617 /* 6618 * Function: 6619 * bcm_tomahawk3_obm_port_pri_traffic_class_mapping_get 6620 * Purpose: 6621 * Determine which COS queue a given priority currently maps to. 6622 * Parameters: 6623 * unit - (IN) unit number 6624 * port - (IN) port number 6625 * priority_type - (IN) Lookup priority type 6626 * obm_tc - (OUT) OBM traffic class to be mapped 6627 * Returns: 6628 * BCM_E_XXX 6629 */ 6630 int 6631 bcm_tomahawk3_obm_port_pri_traffic_class_mapping_get(int unit, bcm_port_t port, 6632 bcm_obm_lookup_priority_type_t piority_type, int priority, 6633 bcm_obm_traffic_class_t *obm_tc) 6634 { 6635 int phy_port, pm_num, pipe, subp; 6636 soc_mem_t mem = INVALIDm; 6637 soc_reg_t reg = INVALIDr; 6638 soc_field_t field = INVALIDf; 6639 soc_info_t *si = &SOC_INFO(unit); 6640 int index, field_val; 6641 uint32 rval; 6642 uint32 entry[SOC_MAX_MEM_WORDS]; 6643 int untag_pri; 6644 6645 if (!SOC_PORT_VALID(unit, port)) { 6646 return BCM_E_PORT; 6647 } 6648 if (priority < 0 || priority >= 8) { 6649 return BCM_E_PARAM; 6650 } 6651 6652 phy_port = si->port_l2p_mapping[port]; 6653 pipe = si->port_pipe[port]; 6654 pm_num = soc_tomahawk3_get_pipe_pm_from_phy_port(phy_port); 6655 subp = soc_tomahawk3_get_subp_from_phy_port(phy_port); 6656 6657 switch(piority_type) { 6658 case bcmObmPriorityTypeVLAN: 6659 mem = SOC_MEM_UNIQUE_ACC_PIPE(unit, obm_pri_map_mem[pm_num][subp], 6660 pipe); 6661 field = obm_ob_pri_fields[priority]; 6662 index = 0; 6663 BCM_IF_ERROR_RETURN( 6664 soc_mem_read(unit, mem, MEM_BLOCK_ANY, index, entry)); 6665 field_val = soc_mem_field32_get(unit, mem, entry, field); 6666 break; 6667 case bcmObmPriorityTypeDSCP: 6668 mem = SOC_MEM_UNIQUE_ACC_PIPE(unit, obm_dscp_map_mem[pm_num][subp], 6669 pipe); 6670 field = obm_ob_pri_fields[priority]; 6671 index = 0; 6672 BCM_IF_ERROR_RETURN( 6673 soc_mem_read(unit, mem, MEM_BLOCK_ANY, index, entry)); 6674 field_val = soc_mem_field32_get(unit, mem, entry, field); 6675 break; 6676 case bcmObmPriorityTypeUntagged: 6677 reg = obm_port_config_regs[pm_num]; 6678 field = PORT_PRIf; 6679 index = subp; 6680 BCM_IF_ERROR_RETURN( 6681 soc_reg32_get(unit, reg, index, 0, &rval)); 6682 untag_pri = soc_reg_field_get(unit, reg, rval, field); 6683 field = obm_ob_pri_fields[untag_pri]; 6684 index = 0; 6685 mem = SOC_MEM_UNIQUE_ACC_PIPE(unit, obm_pri_map_mem[pm_num][subp], 6686 pipe); 6687 BCM_IF_ERROR_RETURN( 6688 soc_mem_read(unit, mem, MEM_BLOCK_ANY, index, entry)); 6689 field_val = soc_mem_field32_get(unit, mem, entry, field); 6690 break; 6691 default: 6692 return BCM_E_PARAM; 6693 } 6694 switch(field_val) { 6695 case 0: 6696 *obm_tc = bcmObmClassLossyLow; 6697 break; 6698 case 1: 6699 *obm_tc = bcmObmClassLossyHigh; 6700 break; 6701 case 2: 6702 *obm_tc = bcmObmClassLossless0; 6703 break; 6704 case 3: 6705 *obm_tc = bcmObmClassLossless1; 6706 break; 6707 default: 6708 return BCM_E_INTERNAL; 6709 } 6710 6711 6712 return BCM_E_NONE; 6713 } 6714 6715 static const soc_reg_t obm_max_use_config_regs[4] = { 6716 IDB_OBM0_MAX_USAGE_SELECTr, IDB_OBM1_MAX_USAGE_SELECTr, 6717 IDB_OBM2_MAX_USAGE_SELECTr, IDB_OBM3_MAX_USAGE_SELECTr 6718 }; 6719 6720 int 6721 bcm_tomahawk3_obm_port_max_usage_mode_get (int unit, bcm_port_t port, 6722 bcm_obm_max_watermark_mode_t *obm_wm_mode) { 6723 int pipe, pm_num, phy_port; 6724 uint32 rval; 6725 soc_field_t field = PRIORITY_SELECTf; 6726 soc_info_t *si = &SOC_INFO(unit); 6727 6728 if (!SOC_PORT_VALID(unit, port)) { 6729 return BCM_E_PORT; 6730 } 6731 6732 phy_port = si->port_l2p_mapping[port]; 6733 pipe = si->port_pipe[port]; 6734 pm_num = soc_tomahawk3_get_pipe_pm_from_phy_port(phy_port); 6735 6736 BCM_IF_ERROR_RETURN( 6737 soc_reg32_get(unit, obm_max_use_config_regs[pm_num], pipe, 0, 6738 &rval)); 6739 *obm_wm_mode = soc_reg_field_get(unit, obm_max_use_config_regs[pm_num], rval, 6740 field); 6741 6742 return BCM_E_NONE; 6743 } 6744 6745 int 6746 bcm_tomahawk3_obm_port_max_usage_mode_set (int unit, bcm_port_t port, 6747 bcm_obm_max_watermark_mode_t obm_wm_mode) { 6748 int pipe, pm_num, phy_port; 6749 int field_val; 6750 uint32 rval; 6751 soc_field_t field = PRIORITY_SELECTf; 6752 soc_info_t *si = &SOC_INFO(unit); 6753 6754 if (!SOC_PORT_VALID(unit, port)) { 6755 return BCM_E_PORT; 6756 } 6757 6758 phy_port = si->port_l2p_mapping[port]; 6759 pipe = si->port_pipe[port]; 6760 pm_num = soc_tomahawk3_get_pipe_pm_from_phy_port(phy_port); 6761 6762 switch(obm_wm_mode) { 6763 case bcmObmMaxUsageModeAllTraffic: 6764 field_val = 0; 6765 break; 6766 case bcmObmMaxUsageModeLossy: 6767 field_val = 1; 6768 break; 6769 case bcmObmMaxUsageModeLossless0: 6770 field_val = 2; 6771 break; 6772 case bcmObmMaxUsageModeLossless1: 6773 field_val = 3; 6774 break; 6775 default: 6776 return BCM_E_PARAM; 6777 6778 } 6779 6780 BCM_IF_ERROR_RETURN( 6781 soc_reg32_get(unit, obm_max_use_config_regs[pm_num], pipe, 0, &rval)); 6782 soc_reg_field_set(unit, obm_max_use_config_regs[pm_num], &rval, field, 6783 field_val); 6784 BCM_IF_ERROR_RETURN( 6785 soc_reg32_set(unit, obm_max_use_config_regs[pm_num], pipe, 0, rval)); 6786 6787 return BCM_E_NONE; 6788 } 6789 6790 static const soc_reg_t obm_priority_profile_regs[4] = { 6791 IDB_OBM0_FLOW_CONTROL_CONFIGr, IDB_OBM1_FLOW_CONTROL_CONFIGr, 6792 IDB_OBM2_FLOW_CONTROL_CONFIGr, IDB_OBM3_FLOW_CONTROL_CONFIGr 6793 }; 6794 6795 int 6796 bcm_tomahawk3_obm_traffic_class_pfc_priority_mapping_set (int unit, bcm_port_t port, 6797 bcm_obm_traffic_class_t obm_tc, int max_pri_count, 6798 int* priority_list) { 6799 6800 int pipe, pm_num, phy_port, subp; 6801 uint64 rval; 6802 soc_field_t field; 6803 soc_info_t *si = &SOC_INFO(unit); 6804 int array_idx, pri_val; 6805 int field_val = 0; 6806 6807 if (!SOC_PORT_VALID(unit, port)) { 6808 return BCM_E_PORT; 6809 } 6810 if (max_pri_count <= 0 || max_pri_count > 8) { 6811 return BCM_E_PARAM; 6812 } 6813 switch (obm_tc) { 6814 case bcmObmClassLossless0: 6815 field = LOSSLESS0_PRIORITY_PROFILEf; 6816 break; 6817 case bcmObmClassLossless1: 6818 field = LOSSLESS1_PRIORITY_PROFILEf; 6819 break; 6820 default: 6821 return BCM_E_PARAM; 6822 } 6823 6824 for (array_idx = 0; array_idx < max_pri_count; array_idx ++) { 6825 pri_val = priority_list[array_idx]; 6826 if (pri_val < 0 || pri_val >= 8) { 6827 return BCM_E_PARAM; 6828 } 6829 field_val |= (1 << pri_val); 6830 } 6831 6832 phy_port = si->port_l2p_mapping[port]; 6833 pipe = si->port_pipe[port]; 6834 pm_num = soc_tomahawk3_get_pipe_pm_from_phy_port(phy_port); 6835 subp = soc_tomahawk3_get_subp_from_phy_port(phy_port); 6836 6837 BCM_IF_ERROR_RETURN( 6838 soc_reg64_get(unit, obm_priority_profile_regs[pm_num], pipe, subp, &rval)); 6839 soc_reg64_field32_set(unit, obm_priority_profile_regs[pm_num], &rval, field, 6840 field_val); 6841 BCM_IF_ERROR_RETURN( 6842 soc_reg64_set(unit, obm_priority_profile_regs[pm_num], pipe, subp, rval)); 6843 6844 return BCM_E_NONE; 6845 } 6846 6847 int 6848 bcm_tomahawk3_obm_traffic_class_pfc_priority_mapping_get (int unit, bcm_port_t port, 6849 bcm_obm_traffic_class_t obm_tc, int max_pri_count, 6850 int* priority_list, int* pri_count) { 6851 6852 int pipe, pm_num, phy_port, subp; 6853 uint64 rval; 6854 soc_field_t field; 6855 soc_info_t *si = &SOC_INFO(unit); 6856 int field_val, pri_val, array_idx = 0; 6857 6858 if (!SOC_PORT_VALID(unit, port)) { 6859 return BCM_E_PORT; 6860 } 6861 if (max_pri_count <= 0 || max_pri_count > 8) { 6862 return BCM_E_PARAM; 6863 } 6864 switch (obm_tc) { 6865 case bcmObmClassLossless0: 6866 field = LOSSLESS0_PRIORITY_PROFILEf; 6867 break; 6868 case bcmObmClassLossless1: 6869 field = LOSSLESS1_PRIORITY_PROFILEf; 6870 break; 6871 default: 6872 return BCM_E_PARAM; 6873 } 6874 6875 phy_port = si->port_l2p_mapping[port]; 6876 pipe = si->port_pipe[port]; 6877 pm_num = soc_tomahawk3_get_pipe_pm_from_phy_port(phy_port); 6878 subp = soc_tomahawk3_get_subp_from_phy_port(phy_port); 6879 6880 BCM_IF_ERROR_RETURN( 6881 soc_reg_get(unit, obm_priority_profile_regs[pm_num], pipe, 6882 subp, &rval)); 6883 field_val = soc_reg64_field32_get(unit, obm_priority_profile_regs[pm_num], rval, 6884 field); 6885 for (pri_val = 0; pri_val < 8 ; pri_val++) { 6886 if ((field_val == 0) || (array_idx == max_pri_count)) { 6887 break; 6888 } 6889 if ((field_val >> pri_val) & 1) { 6890 priority_list[array_idx++] = pri_val; 6891 } 6892 } 6893 *pri_count = array_idx; 6894 return BCM_E_NONE; 6895 } 6896 6897 /* 6898 * Function: 6899 * _bcm_th3_cosq_bucket_set 6900 * Purpose: 6901 * Get COS queue bandwidth control bucket setting 6902 * Parameters: 6903 * unit - (IN) unit number 6904 * gport - (IN) port number or GPORT identifier 6905 * cosq - (IN) COS queue number 6906 * min_quantum - (OUT) kbps or packet/second 6907 * max_quantum - (OUT) kbps or packet/second 6908 * burst_quantum - (OUT) kbps or packet/second 6909 * flags - (IN) 6910 * Returns: 6911 * BCM_E_XXX 6912 * Notes: 6913 * If port is any form of local port, cosq is the hardware queue index. 6914 */ 6915 STATIC int 6916 _bcm_th3_cosq_bucket_set(int unit, bcm_port_t gport, bcm_cos_queue_t cosq, 6917 uint32 min_quantum, uint32 max_quantum, 6918 uint32 kbits_burst_min, uint32 kbits_burst_max, 6919 uint32 flags) 6920 { 6921 _bcm_th3_cosq_node_t *node = NULL; 6922 bcm_port_t local_port; 6923 uint32 rval, meter_flags; 6924 uint32 bucketsize_max, bucketsize_min; 6925 uint32 granularity_max, granularity_min; 6926 uint32 refresh_rate_max, refresh_rate_min; 6927 int refresh_bitsize = 0, bucket_bitsize = 0; 6928 int pipe, local_mmu_port, index; 6929 soc_mem_t config_mem = INVALIDm; 6930 uint32 entry[SOC_MAX_MEM_WORDS]; 6931 soc_info_t *si = &SOC_INFO(unit); 6932 int cpu_mc_base = 0; 6933 6934 if (cosq < 0) { 6935 if (cosq == -1) { 6936 /* caller needs to resolve the wild card value (-1) */ 6937 return BCM_E_INTERNAL; 6938 } else { /* reject all other negative value */ 6939 return BCM_E_PARAM; 6940 } 6941 } 6942 6943 BCM_IF_ERROR_RETURN 6944 (_bcm_th3_cosq_localport_resolve(unit, gport, &local_port)); 6945 6946 BCM_IF_ERROR_RETURN(soc_port_pipe_get(unit, local_port, &pipe)); 6947 6948 local_mmu_port = SOC_TH3_MMU_LOCAL_PORT(unit, local_port); 6949 6950 if (BCM_GPORT_IS_SET(gport) && 6951 ((BCM_GPORT_IS_SCHEDULER(gport)) || 6952 BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport) || 6953 BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport) || 6954 BCM_GPORT_IS_UCAST_SUBSCRIBER_QUEUE_GROUP(gport))) { 6955 6956 BCM_IF_ERROR_RETURN 6957 (_bcm_th3_cosq_node_get(unit, gport, NULL, 6958 NULL, NULL, &node)); 6959 } 6960 6961 if (node) { 6962 if (BCM_GPORT_IS_SCHEDULER(gport)) { 6963 if (node->level == SOC_TH3_NODE_LVL_L0) { 6964 config_mem = SOC_MEM_UNIQUE_ACC(unit, MMU_MTRO_L0_Am)[pipe]; 6965 cosq = node->hw_index % _BCM_TH3_NUM_SCHEDULER_PER_PORT; 6966 index = ((local_mmu_port & (SOC_TH3_MMU_PORT_STRIDE - 1)) * 6967 _BCM_TH3_NUM_SCHEDULER_PER_PORT) + cosq; 6968 } else { 6969 return BCM_E_PARAM; 6970 } 6971 } else if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 6972 /* L1 level metering is supported only for CPU. 6973 CPU has only multicast queues. 6974 So cannot be Unicast type */ 6975 return BCM_E_PARAM; 6976 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 6977 /* L1 level metering is supported only for CPU */ 6978 if (!IS_CPU_PORT(unit, local_port)) { 6979 return BCM_E_PORT; 6980 } 6981 config_mem = MMU_MTRO_CPU_L1_Am; 6982 cosq = node->hw_index % si->port_num_cosq[local_port]; 6983 6984 /*Adjust mc cosq for cpu port*/ 6985 cpu_mc_base = si->port_cosq_base[CMIC_PORT(unit)]; 6986 cosq = (node->hw_index - cpu_mc_base) % 6987 _BCM_TH3_NUM_CPU_MCAST_QUEUE; 6988 index = cosq; 6989 } else { 6990 return BCM_E_PARAM; 6991 } 6992 } else { 6993 if ((cosq < 0) || (cosq >= _TH3_PORT_NUM_COS(unit, local_port))) { 6994 return BCM_E_PARAM; 6995 } 6996 if (!IS_CPU_PORT(unit, local_port)) { 6997 index = ((local_mmu_port & (SOC_TH3_MMU_PORT_STRIDE - 1)) * 6998 _BCM_TH3_NUM_SCHEDULER_PER_PORT) + cosq; 6999 config_mem = SOC_MEM_UNIQUE_ACC(unit, MMU_MTRO_L0_Am)[pipe]; 7000 } else { 7001 /* For CPU port, refer L1 memory directly */ 7002 config_mem = MMU_MTRO_CPU_L1_Am; 7003 7004 index = cosq; 7005 } 7006 } 7007 7008 /* 7009 * COVERITY 7010 * 7011 * This checker will not be True. 7012 * It is kept intentionally as a defensive case for future development. 7013 */ 7014 /* coverity[dead_error_line] */ 7015 if (config_mem == INVALIDm) { 7016 return BCM_E_PARAM; 7017 } 7018 7019 meter_flags = flags & BCM_COSQ_BW_PACKET_MODE ? 7020 _BCM_TH3_METER_FLAG_PACKET_MODE : 0; 7021 7022 BCM_IF_ERROR_RETURN(READ_MMU_MTRO_CONFIGr(unit, &rval)); 7023 if (soc_reg_field_get(unit, MMU_MTRO_CONFIGr, rval, ITU_MODE_SELf)) { 7024 meter_flags |= _BCM_TH3_METER_FLAG_NON_LINEAR; 7025 } 7026 7027 7028 refresh_bitsize = soc_mem_field_length(unit, config_mem, MAX_REFRESHf); 7029 bucket_bitsize = soc_mem_field_length(unit, config_mem, MAX_THD_SELf); 7030 BCM_IF_ERROR_RETURN 7031 (_bcm_th3_rate_to_bucket_encoding(unit, max_quantum, kbits_burst_max, 7032 meter_flags, refresh_bitsize, 7033 bucket_bitsize, &refresh_rate_max, 7034 &bucketsize_max, &granularity_max)); 7035 7036 refresh_bitsize = soc_mem_field_length(unit, config_mem, MIN_REFRESHf); 7037 bucket_bitsize = soc_mem_field_length(unit, config_mem, MIN_THD_SELf); 7038 BCM_IF_ERROR_RETURN 7039 (_bcm_th3_rate_to_bucket_encoding(unit, min_quantum, kbits_burst_min, 7040 meter_flags, refresh_bitsize, 7041 bucket_bitsize, &refresh_rate_min, 7042 &bucketsize_min, &granularity_min)); 7043 7044 sal_memset(entry, 0, sizeof(uint32)*SOC_MAX_MEM_WORDS); 7045 soc_mem_field32_set(unit, config_mem, &entry, MAX_METER_GRANf, granularity_max); 7046 soc_mem_field32_set(unit, config_mem, &entry, MAX_REFRESHf, refresh_rate_max); 7047 soc_mem_field32_set(unit, config_mem, &entry, MAX_THD_SELf, bucketsize_max); 7048 soc_mem_field32_set(unit, config_mem, &entry, MIN_METER_GRANf, granularity_min); 7049 soc_mem_field32_set(unit, config_mem, &entry, MIN_REFRESHf, refresh_rate_min); 7050 soc_mem_field32_set(unit, config_mem, &entry, MIN_THD_SELf, bucketsize_min); 7051 soc_mem_field32_set(unit, config_mem, &entry, PACKET_SHAPINGf, (flags & BCM_COSQ_BW_PACKET_MODE) ? 1 : 0); 7052 BCM_IF_ERROR_RETURN 7053 (soc_mem_write(unit, config_mem, MEM_BLOCK_ALL, index, &entry)); 7054 7055 return BCM_E_NONE; 7056 } 7057 7058 7059 /* 7060 * Function: 7061 * _bcm_th3_cosq_bucket_get 7062 * Purpose: 7063 * Get COS queue bandwidth control bucket setting 7064 * Parameters: 7065 * unit - (IN) unit number 7066 * gport - (IN) port number or GPORT identifier 7067 * cosq - (IN) COS queue number 7068 * min_quantum - (OUT) kbps or packet/second 7069 * max_quantum - (OUT) kbps or packet/second 7070 * burst_quantum - (OUT) kbps or packet/second 7071 * flags - (IN) 7072 * Returns: 7073 * BCM_E_XXX 7074 * Notes: 7075 * If port is any form of local port, cosq is the hardware queue index. 7076 */ 7077 STATIC int 7078 _bcm_th3_cosq_bucket_get(int unit, bcm_port_t gport, bcm_cos_queue_t cosq, 7079 uint32 *min_quantum, uint32 *max_quantum, 7080 uint32 *kbits_burst_min, uint32 *kbits_burst_max, 7081 uint32 *flags) 7082 { 7083 _bcm_th3_cosq_node_t *node = NULL; 7084 bcm_port_t local_port; 7085 uint32 rval; 7086 int local_mmu_port, index; 7087 soc_mem_t config_mem = INVALIDm; 7088 uint32 entry[SOC_MAX_MEM_WORDS]; 7089 soc_info_t *si = &SOC_INFO(unit); 7090 int cpu_mc_base = 0; 7091 int pipe; 7092 uint32 refresh_rate, bucketsize, granularity, meter_flags; 7093 7094 meter_flags = 0; 7095 7096 LOG_INFO(BSL_LS_BCM_COSQ, 7097 (BSL_META_U(unit, 7098 "gport: %d cosq: %d\n"), 7099 gport, cosq)); 7100 if (cosq < 0) { 7101 if (cosq == -1) { 7102 /* caller needs to resolve the wild card value (-1) */ 7103 return BCM_E_INTERNAL; 7104 } else { /* reject all other negative value */ 7105 return BCM_E_PARAM; 7106 } 7107 } 7108 7109 BCM_IF_ERROR_RETURN 7110 (_bcm_th3_cosq_localport_resolve(unit, gport, &local_port)); 7111 pipe = si->port_pipe[local_port]; 7112 7113 local_mmu_port = SOC_TH3_MMU_LOCAL_PORT(unit, local_port); 7114 7115 if (BCM_GPORT_IS_SET(gport) && 7116 ((BCM_GPORT_IS_SCHEDULER(gport)) || 7117 BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport) || 7118 BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport) || 7119 BCM_GPORT_IS_UCAST_SUBSCRIBER_QUEUE_GROUP(gport))) { 7120 7121 BCM_IF_ERROR_RETURN 7122 (_bcm_th3_cosq_node_get(unit, gport, NULL, 7123 NULL, NULL, &node)); 7124 } 7125 7126 if (node) { 7127 if (BCM_GPORT_IS_SCHEDULER(gport)) { 7128 if (node->level == SOC_TH3_NODE_LVL_L0) { 7129 config_mem = SOC_MEM_UNIQUE_ACC(unit, MMU_MTRO_L0_Am)[pipe]; 7130 cosq = node->hw_index % _BCM_TH3_NUM_SCHEDULER_PER_PORT; 7131 index = ((local_mmu_port & (SOC_TH3_MMU_PORT_STRIDE - 1)) * 7132 _BCM_TH3_NUM_SCHEDULER_PER_PORT) + cosq; 7133 } else { 7134 return BCM_E_PARAM; 7135 } 7136 } else if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 7137 /* L1 level metering is supported only for CPU 7138 so cannot be Unicast type */ 7139 return BCM_E_PARAM; 7140 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 7141 /* L1 level metering is supported only for CPU */ 7142 if (!IS_CPU_PORT(unit, local_port)) { 7143 return BCM_E_PORT; 7144 } 7145 config_mem = MMU_MTRO_CPU_L1_Am; 7146 cosq = node->hw_index % si->port_num_cosq[local_port]; 7147 7148 /*Adjust mc cosq for cpu port*/ 7149 cpu_mc_base = si->port_cosq_base[CMIC_PORT(unit)]; 7150 cosq = (node->hw_index - cpu_mc_base) % 7151 _BCM_TH3_NUM_CPU_MCAST_QUEUE; 7152 index = cosq; 7153 } else { 7154 return BCM_E_PARAM; 7155 } 7156 } else { 7157 if ((cosq < 0) || (cosq >= _TH3_PORT_NUM_COS(unit, local_port))) { 7158 return BCM_E_PARAM; 7159 } 7160 if (!IS_CPU_PORT(unit, local_port)) { 7161 index = ((local_mmu_port & (SOC_TH3_MMU_PORT_STRIDE - 1)) * 7162 _BCM_TH3_NUM_SCHEDULER_PER_PORT) + cosq; 7163 config_mem = SOC_MEM_UNIQUE_ACC(unit, MMU_MTRO_L0_Am)[pipe]; 7164 } else { 7165 /* For CPU port, refer L1 memory directly */ 7166 config_mem = MMU_MTRO_CPU_L1_Am; 7167 index = cosq; 7168 } 7169 } 7170 7171 /* 7172 * COVERITY 7173 * 7174 * This checker will not be True. 7175 * It is kept intentionally as a defensive case for future development. 7176 */ 7177 /* coverity[dead_error_line] */ 7178 if (config_mem == INVALIDm) { 7179 return BCM_E_PARAM; 7180 } 7181 7182 /* index = SOC_TH3_MMU_PIPED_MEM_INDEX(unit, local_port, config_mem, index); */ 7183 7184 if (min_quantum == NULL || max_quantum == NULL || 7185 kbits_burst_max == NULL || kbits_burst_min == NULL) { 7186 return BCM_E_PARAM; 7187 } 7188 7189 BCM_IF_ERROR_RETURN 7190 (soc_mem_read(unit, config_mem, MEM_BLOCK_ALL, index, &entry)); 7191 7192 *flags = 0; 7193 BCM_IF_ERROR_RETURN(READ_MMU_MTRO_CONFIGr(unit, &rval)); 7194 if (soc_reg_field_get(unit, MMU_MTRO_CONFIGr, rval, ITU_MODE_SELf)) { 7195 meter_flags |= _BCM_TH3_METER_FLAG_NON_LINEAR; 7196 } 7197 7198 if (soc_mem_field32_get(unit, config_mem, &entry, PACKET_SHAPINGf)) { 7199 meter_flags |= _BCM_TH3_METER_FLAG_PACKET_MODE; 7200 *flags |= BCM_COSQ_BW_PACKET_MODE; 7201 } 7202 7203 granularity = soc_mem_field32_get(unit, config_mem, &entry, MAX_METER_GRANf); 7204 refresh_rate = soc_mem_field32_get(unit, config_mem, &entry, MAX_REFRESHf); 7205 bucketsize = soc_mem_field32_get(unit, config_mem, &entry, MAX_THD_SELf); 7206 BCM_IF_ERROR_RETURN 7207 (_bcm_th3_bucket_encoding_to_rate(unit, refresh_rate, bucketsize, 7208 granularity, meter_flags, 7209 max_quantum, kbits_burst_max)); 7210 7211 granularity = soc_mem_field32_get(unit, config_mem, &entry, MIN_METER_GRANf); 7212 refresh_rate = soc_mem_field32_get(unit, config_mem, &entry, MIN_REFRESHf); 7213 bucketsize = soc_mem_field32_get(unit, config_mem, &entry, MIN_THD_SELf); 7214 BCM_IF_ERROR_RETURN 7215 (_bcm_th3_bucket_encoding_to_rate(unit, refresh_rate, bucketsize, 7216 granularity, meter_flags, 7217 min_quantum, kbits_burst_min)); 7218 return BCM_E_NONE; 7219 } 7220 7221 /* 7222 * Function: 7223 * bcm_th3_cosq_port_bandwidth_set 7224 * Purpose: 7225 * Configure COS queue bandwidth control 7226 * Parameters: 7227 * unit - (IN) unit number 7228 * port - (IN) port number or GPORT identifier 7229 * cosq - (IN) COS queue number 7230 * min_quantum - (IN) 7231 * max_quantum - (IN) 7232 * burst_quantum - (IN) 7233 * flags - (IN) 7234 * Returns: 7235 * BCM_E_XXX 7236 * Notes: 7237 * If port is any form of local port, cosq is the hardware queue index. 7238 */ 7239 int 7240 bcm_th3_cosq_port_bandwidth_set(int unit, bcm_port_t port, 7241 bcm_cos_queue_t cosq, 7242 uint32 min_quantum, uint32 max_quantum, 7243 uint32 burst_quantum, uint32 flags) 7244 { 7245 return bcm_th3_cosq_gport_bandwidth_set(unit, port, cosq, 7246 min_quantum, max_quantum, 7247 flags); 7248 } 7249 7250 7251 /* 7252 * Function: 7253 * bcm_th3_cosq_port_bandwidth_get 7254 * Purpose: 7255 * Get COS queue bandwidth control configuration 7256 * Parameters: 7257 * unit - (IN) unit number 7258 * port - (IN) port number or GPORT identifier 7259 * cosq - (IN) COS queue number 7260 * min_quantum - (OUT) 7261 * max_quantum - (OUT) 7262 * burst_quantum - (OUT) 7263 * flags - (OUT) 7264 * Returns: 7265 * BCM_E_XXX 7266 * Notes: 7267 * If port is any form of local port, cosq is the hardware queue index. 7268 */ 7269 7270 int 7271 bcm_th3_cosq_port_bandwidth_get(int unit, bcm_port_t port, 7272 bcm_cos_queue_t cosq, 7273 uint32 *min_quantum, uint32 *max_quantum, 7274 uint32 *burst_quantum, uint32 *flags) 7275 { 7276 return bcm_th3_cosq_gport_bandwidth_get(unit, port, cosq, 7277 min_quantum, max_quantum, 7278 flags); 7279 } 7280 7281 /* 7282 * Function: 7283 * bcm_th3_cosq_gport_bandwidth_burst_get 7284 * Purpose: 7285 * Get COS queue bandwidth burst setting 7286 * Parameters: 7287 * unit - (IN) unit number 7288 * gport - (IN) GPORT identifier 7289 * cosq - (IN) COS queue to get, -1 for Queue 0 7290 * kbits_burst - (OUT) maximum burst, kbits 7291 * Returns: 7292 * BCM_E_XXX 7293 */ 7294 int 7295 bcm_th3_cosq_gport_bandwidth_burst_get(int unit, bcm_gport_t gport, 7296 bcm_cos_queue_t cosq, 7297 uint32 *kbits_burst_min, 7298 uint32 *kbits_burst_max) 7299 { 7300 uint32 kbits_sec_min, kbits_sec_max, flags; 7301 7302 if (cosq < -1) { 7303 return BCM_E_PARAM; 7304 } 7305 7306 BCM_IF_ERROR_RETURN 7307 (_bcm_th3_cosq_bucket_get(unit, gport, cosq == -1 ? 0 : cosq, 7308 &kbits_sec_min, &kbits_sec_max, kbits_burst_min, 7309 kbits_burst_max, &flags)); 7310 7311 return BCM_E_NONE; 7312 } 7313 7314 /* 7315 * Function: 7316 * bcm_th3_cosq_gport_bandwidth_burst_set 7317 * Purpose: 7318 * Configure COS queue bandwidth burst setting 7319 * Parameters: 7320 * unit - (IN) unit number 7321 * gport - (IN) GPORT identifier 7322 * cosq - (IN) COS queue to configure, -1 for all COS queues 7323 * kbits_burst - (IN) maximum burst, kbits 7324 * Returns: 7325 * BCM_E_XXX 7326 */ 7327 7328 int 7329 bcm_th3_cosq_gport_bandwidth_burst_set(int unit, bcm_gport_t gport, 7330 bcm_cos_queue_t cosq, 7331 uint32 kbits_burst_min, 7332 uint32 kbits_burst_max) 7333 { 7334 int i, start_cos=0, end_cos=0; 7335 uint32 kbits_sec_min, kbits_sec_max, kbits_sec_burst, flags; 7336 bcm_port_t local_port; 7337 7338 BCM_IF_ERROR_RETURN 7339 (_bcm_th3_cosq_localport_resolve(unit, gport, &local_port)); 7340 7341 start_cos = end_cos = cosq; 7342 7343 if (cosq == BCM_COS_INVALID) { 7344 start_cos = 0; 7345 end_cos = (IS_CPU_PORT(unit, local_port)) ? 7346 NUM_CPU_COSQ(unit) - 1 : _TH3_PORT_NUM_COS(unit, local_port) 7347 - 1; 7348 } 7349 7350 if (BCM_GPORT_IS_SET(gport)) { 7351 if ((BCM_GPORT_IS_SCHEDULER(gport)) || 7352 BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport) || 7353 BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 7354 start_cos = end_cos = 0; 7355 } 7356 } 7357 7358 for (i = start_cos; i <= end_cos; i++) { 7359 BCM_IF_ERROR_RETURN 7360 (_bcm_th3_cosq_bucket_get(unit, gport, i, &kbits_sec_min, 7361 &kbits_sec_max, &kbits_sec_burst, 7362 &kbits_sec_burst, &flags)); 7363 BCM_IF_ERROR_RETURN 7364 (_bcm_th3_cosq_bucket_set(unit, gport, i, kbits_sec_min, 7365 kbits_sec_max, kbits_burst_min, 7366 kbits_burst_max, flags)); 7367 } 7368 return BCM_E_NONE; 7369 } 7370 7371 int 7372 bcm_th3_cosq_port_pps_set(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 7373 int pps) 7374 { 7375 uint32 min, max, burst, burst_min, flags; 7376 bcm_port_t local_port = port; 7377 7378 if (!IS_CPU_PORT(unit, port)) { 7379 return BCM_E_PORT; 7380 } else if (cosq < 0 || cosq >= NUM_CPU_COSQ(unit)) { 7381 return BCM_E_PARAM; 7382 } 7383 7384 if (BCM_GPORT_IS_SET(port) && 7385 ((BCM_GPORT_IS_SCHEDULER(port)) || 7386 BCM_GPORT_IS_UCAST_QUEUE_GROUP(port) || 7387 BCM_GPORT_IS_MCAST_QUEUE_GROUP(port) || 7388 BCM_GPORT_IS_UCAST_SUBSCRIBER_QUEUE_GROUP(port))) { 7389 return BCM_E_UNAVAIL; 7390 } 7391 7392 BCM_IF_ERROR_RETURN 7393 (_bcm_th3_cosq_bucket_get(unit, port, cosq, &min, &max, &burst_min, 7394 &burst, &flags)); 7395 min = pps; 7396 burst_min = (min > 0) ? 7397 _bcm_th3_default_burst_size(unit, local_port, min) : 0; 7398 burst = burst_min; 7399 7400 return _bcm_th3_cosq_bucket_set(unit, port, cosq, min, pps, burst_min, 7401 burst, flags | BCM_COSQ_BW_PACKET_MODE); 7402 } 7403 7404 int 7405 bcm_th3_cosq_port_pps_get(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 7406 int *pps) 7407 { 7408 uint32 min, max, burst, flags; 7409 7410 if (!IS_CPU_PORT(unit, port)) { 7411 return BCM_E_PORT; 7412 } else if (cosq < 0 || cosq >= NUM_CPU_COSQ(unit)) { 7413 return BCM_E_PARAM; 7414 } 7415 7416 if (BCM_GPORT_IS_SET(port) && 7417 ((BCM_GPORT_IS_SCHEDULER(port)) || 7418 BCM_GPORT_IS_UCAST_QUEUE_GROUP(port) || 7419 BCM_GPORT_IS_MCAST_QUEUE_GROUP(port) || 7420 BCM_GPORT_IS_UCAST_SUBSCRIBER_QUEUE_GROUP(port))) { 7421 return BCM_E_UNAVAIL; 7422 } 7423 7424 BCM_IF_ERROR_RETURN 7425 (_bcm_th3_cosq_bucket_get(unit, port, cosq, &min, &max, &burst, &burst, 7426 &flags)); 7427 *pps = max; 7428 7429 return BCM_E_NONE; 7430 } 7431 7432 int 7433 bcm_th3_cosq_port_burst_set(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 7434 int burst) 7435 { 7436 uint32 min, max, cur_burst, flags; 7437 7438 if (!IS_CPU_PORT(unit, port)) { 7439 return BCM_E_PORT; 7440 } else if (cosq < 0 || cosq >= NUM_CPU_COSQ(unit)) { 7441 return BCM_E_PARAM; 7442 } 7443 7444 if (BCM_GPORT_IS_SET(port) && 7445 ((BCM_GPORT_IS_SCHEDULER(port)) || 7446 BCM_GPORT_IS_UCAST_QUEUE_GROUP(port) || 7447 BCM_GPORT_IS_MCAST_QUEUE_GROUP(port) || 7448 BCM_GPORT_IS_UCAST_SUBSCRIBER_QUEUE_GROUP(port))) { 7449 return BCM_E_UNAVAIL; 7450 } 7451 7452 BCM_IF_ERROR_RETURN 7453 (_bcm_th3_cosq_bucket_get(unit, port, cosq, &min, &max, &cur_burst, 7454 &cur_burst, &flags)); 7455 7456 /* Replace the current BURST setting, keep PPS the same */ 7457 7458 return _bcm_th3_cosq_bucket_set(unit, port, cosq, min, max, burst, burst, 7459 flags | BCM_COSQ_BW_PACKET_MODE); 7460 return BCM_E_NONE; 7461 } 7462 7463 int 7464 bcm_th3_cosq_port_burst_get(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 7465 int *burst) 7466 { 7467 uint32 min, max, cur_burst, cur_burst_min, flags; 7468 7469 if (!IS_CPU_PORT(unit, port)) { 7470 return BCM_E_PORT; 7471 } else if (cosq < 0 || cosq >= NUM_CPU_COSQ(unit)) { 7472 return BCM_E_PARAM; 7473 } 7474 7475 if (BCM_GPORT_IS_SET(port) && 7476 ((BCM_GPORT_IS_SCHEDULER(port)) || 7477 BCM_GPORT_IS_UCAST_QUEUE_GROUP(port) || 7478 BCM_GPORT_IS_MCAST_QUEUE_GROUP(port) || 7479 BCM_GPORT_IS_UCAST_SUBSCRIBER_QUEUE_GROUP(port))) { 7480 return BCM_E_PARAM; 7481 } 7482 7483 BCM_IF_ERROR_RETURN 7484 (_bcm_th3_cosq_bucket_get(unit, port, cosq, &min, &max, 7485 &cur_burst_min, &cur_burst, &flags)); 7486 *burst = cur_burst; 7487 return BCM_E_NONE; 7488 } 7489 7490 STATIC int 7491 _bcm_th3_cosq_time_domain_set(int unit, int time_value, int *time_id) 7492 { 7493 int id; 7494 uint32 time_domain_val; 7495 soc_reg_t time_domain_reg = MMU_WRED_TIME_DOMAINr; 7496 7497 if (time_value < 0 || time_value > 63) { 7498 return SOC_E_PARAM; 7499 } 7500 7501 for (id = 0; id < _BCM_TH3_NUM_TIME_DOMAIN; id++) { 7502 BCM_IF_ERROR_RETURN( 7503 soc_reg32_get(unit, time_domain_reg, REG_PORT_ANY, id, &time_domain_val)); 7504 if (!th3_time_domain_info[unit][id].ref_count) { 7505 soc_reg_field_set(unit, time_domain_reg, &time_domain_val, 7506 TIME_DOMAIN_FIELDf, time_value); 7507 th3_time_domain_info[unit][id].ref_count++; 7508 break; 7509 } 7510 } 7511 7512 if (id == _BCM_TH3_NUM_TIME_DOMAIN) {/* No field in TIME_DOMAINr is free,return ERR*/ 7513 return BCM_E_RESOURCE; 7514 } 7515 7516 if (time_id) { 7517 *time_id = id; 7518 } 7519 BCM_IF_ERROR_RETURN( 7520 soc_reg32_set(unit, time_domain_reg, REG_PORT_ANY, id, time_domain_val)); 7521 return BCM_E_NONE; 7522 } 7523 7524 STATIC int 7525 _bcm_th3_cosq_time_domain_get(int unit, int time_id, int *time_value) 7526 { 7527 uint32 time_domain_val; 7528 soc_reg_t time_domain_reg = MMU_WRED_TIME_DOMAINr; 7529 7530 if (time_id < 0 || time_id > _BCM_TH3_NUM_TIME_DOMAIN - 1) { 7531 return SOC_E_PARAM; 7532 } 7533 7534 if (time_value == NULL) { 7535 return SOC_E_PARAM; 7536 } 7537 7538 BCM_IF_ERROR_RETURN( 7539 soc_reg32_get(unit, time_domain_reg, REG_PORT_ANY, time_id, &time_domain_val)); 7540 *time_value = soc_reg_field_get(unit, time_domain_reg, 7541 time_domain_val, TIME_DOMAIN_FIELDf); 7542 return SOC_E_NONE; 7543 } 7544 7545 7546 /* 7547 * Function: 7548 * _bcm_th3_cosq_wred_set 7549 * Purpose: 7550 * Configure unicast queue WRED setting 7551 * Parameters: 7552 * unit - (IN) unit number 7553 * port - (IN) port number or GPORT identifier 7554 * cosq - (IN) COS queue number 7555 * flags - (IN) BCM_COSQ_DISCARD_XXX 7556 * min_thresh - (IN) Min Threshold 7557 * max_thresh - (IN) Max Threshold 7558 * drop_probablity - (IN) Probabilistic drop rate 7559 * gain - (IN) 7560 * ignore_enable_flags - (IN) 7561 * lflags - (IN) Config Flags 7562 * refresh_time - (IN) actual refresh time 7563 * Returns: 7564 * BCM_E_XXX 7565 * Notes: 7566 * If port is any form of local port, cosq is the hardware queue index. 7567 */ 7568 STATIC int 7569 _bcm_th3_cosq_wred_set(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 7570 bcm_cosq_buffer_id_t buffer, 7571 uint32 flags, uint32 min_thresh, uint32 max_thresh, 7572 int drop_probability, int gain, int ignore_enable_flags, 7573 uint32 lflags, int refresh_time, uint32 resolution_id) 7574 { 7575 /* Local Variables */ 7576 soc_mem_t wred_config_mem = INVALIDm; 7577 soc_reg_t wred_config_reg = INVALIDr; 7578 bcm_port_t local_port = -1; 7579 bcm_port_t port_num; 7580 int index, i, start_index, end_index, count = 0; 7581 int end_offset, need_profile = 0, pipe, itm, itm_map, accessed = 0; 7582 uint32 profile_index, old_profile_index; 7583 uint32 wred_flags = 0; 7584 void *entries[_BCM_TH3_NUM_WRED_PROFILES]; 7585 soc_mem_t mems[_BCM_TH3_NUM_WRED_PROFILES]; 7586 static soc_mem_t wred_mems[_BCM_TH3_NUM_WRED_PROFILES] = { 7587 MMU_WRED_DROP_CURVE_PROFILE_0_0m, MMU_WRED_DROP_CURVE_PROFILE_1_0m, 7588 MMU_WRED_DROP_CURVE_PROFILE_2_0m, MMU_WRED_DROP_CURVE_PROFILE_3_0m, 7589 MMU_WRED_DROP_CURVE_PROFILE_4_0m, MMU_WRED_DROP_CURVE_PROFILE_5_0m, 7590 MMU_WRED_DROP_CURVE_PROFILE_6_0m, MMU_WRED_DROP_CURVE_PROFILE_7_0m, 7591 MMU_WRED_DROP_CURVE_PROFILE_8_0m 7592 }; 7593 mmu_wred_drop_curve_profile_0_entry_t entry_tcp_green; 7594 mmu_wred_drop_curve_profile_1_entry_t entry_tcp_yellow; 7595 mmu_wred_drop_curve_profile_2_entry_t entry_tcp_red; 7596 mmu_wred_drop_curve_profile_3_entry_t entry_nontcp_green; 7597 mmu_wred_drop_curve_profile_4_entry_t entry_nontcp_yellow; 7598 mmu_wred_drop_curve_profile_5_entry_t entry_nontcp_red; 7599 mmu_wred_drop_curve_profile_6_entry_t entry_ecn_green; 7600 mmu_wred_drop_curve_profile_7_entry_t entry_ecn_yellow; 7601 mmu_wred_drop_curve_profile_8_entry_t entry_ecn_red; 7602 /* mmu_wred_config_entry_t entry; */ 7603 uint32 entry = 0; 7604 int rate = 0; 7605 int from_pipe, to_pipe; 7606 int time_id,time,old_time,current_time_sel; 7607 int rv = SOC_E_NONE, exists = 0; 7608 int device_setting, portsp_setting, queue_setting; 7609 7610 device_setting = 0; 7611 portsp_setting = 0; 7612 queue_setting = 0; 7613 7614 LOG_INFO(BSL_LS_BCM_COSQ, 7615 (BSL_META_U(unit, "_bcm_th3_cosq_wred_set: port: %d cosq: %d min_thres: %d max_thresh: %d flags: %x\n"), 7616 port, cosq, min_thresh, max_thresh, flags)); 7617 if ((buffer != BCM_COSQ_BUFFER_ID_INVALID) && 7618 ((buffer < 0) || (buffer >= _TH3_ITMS_PER_DEV))) { 7619 return BCM_E_PARAM; 7620 } 7621 7622 wred_flags = flags | lflags; 7623 end_offset = 0; 7624 7625 /* Check Flags for WRED res level - Device-SP/Port-SP/Queues */ 7626 if ((wred_flags & BCM_COSQ_DISCARD_DEVICE) && (port == BCM_GPORT_INVALID)) { 7627 /* (Port == -1) For all Global SPs */ 7628 wred_config_reg = MMU_WRED_POOL_CONFIGr; 7629 wred_config_mem = MMU_WRED_QUEUE_CONFIGm; 7630 index = 0; 7631 count = _TH3_MMU_NUM_POOL; 7632 /*For all pipe*/ 7633 from_pipe = 0; 7634 to_pipe = NUM_PIPE(unit) - 1; 7635 device_setting = 1; 7636 } else { 7637 BCM_IF_ERROR_RETURN 7638 (_bcm_th3_cosq_localport_resolve(unit, port, &local_port)); 7639 SOC_IF_ERROR_RETURN(soc_port_pipe_get(unit, local_port, &pipe)); 7640 from_pipe = to_pipe = pipe; 7641 7642 if (wred_flags & BCM_COSQ_DISCARD_DEVICE) { 7643 wred_config_reg = MMU_WRED_POOL_CONFIGr; 7644 device_setting = 1; 7645 BCM_IF_ERROR_RETURN 7646 (_bcm_th3_cosq_index_resolve(unit, port, cosq, 7647 _BCM_TH3_COSQ_INDEX_STYLE_WRED_DEVICE, 7648 NULL, &index, &count)); 7649 /* (cosq == -1) For all Global SPs */ 7650 LOG_INFO(BSL_LS_BCM_COSQ, 7651 (BSL_META_U(unit, "_bcm_th3_cosq_wred_set: Device settings port: %d cosq: %d index: %d count: %d\n"), 7652 port, cosq, index, count)); 7653 } else if (wred_flags & BCM_COSQ_DISCARD_PORT) { 7654 /* Port SP - Given or all SPs of the port */ 7655 wred_config_mem = MMU_WRED_PORTSP_CONFIGm; 7656 portsp_setting = 1; 7657 BCM_IF_ERROR_RETURN 7658 (_bcm_th3_cosq_index_resolve(unit, port, cosq, 7659 _BCM_TH3_COSQ_INDEX_STYLE_WRED_PORT, 7660 NULL, &index, &count)); 7661 /* (cosq == -1) For all SPs of the given port */ 7662 LOG_INFO(BSL_LS_BCM_COSQ, 7663 (BSL_META_U(unit, "_bcm_th3_cosq_wred_set: Port settings port: %d cosq: %d index: %d count: %d\n"), 7664 port, cosq, index, count)); 7665 } else { 7666 /* Per Queue WRED settings */ 7667 wred_config_mem = MMU_WRED_QUEUE_CONFIGm; 7668 queue_setting = 1; 7669 BCM_IF_ERROR_RETURN 7670 (_bcm_th3_cosq_index_resolve(unit, port, cosq, 7671 _BCM_TH3_COSQ_INDEX_STYLE_WRED_QUEUE, 7672 NULL, &index, &count)); 7673 /* (cosq == -1) For all Queues of the given port */ 7674 LOG_INFO(BSL_LS_BCM_COSQ, 7675 (BSL_META_U(unit, "_bcm_th3_cosq_wred_set: Queue settings port: %d cosq: %d index: %d count: %d\n"), 7676 port, cosq, index, count)); 7677 } 7678 } 7679 7680 7681 end_offset = (count > 0) ? (count - 1) : 0; 7682 7683 if (index < 0) { 7684 return BCM_E_PARAM; 7685 } 7686 if (refresh_time < 1) { 7687 return BCM_E_PARAM; 7688 } 7689 start_index = index; 7690 end_index = start_index + end_offset; 7691 7692 rate = _bcm_th3_percent_to_drop_prob(drop_probability); 7693 7694 LOG_INFO(BSL_LS_BCM_COSQ, 7695 (BSL_META_U(unit, "_bcm_th3_cosq_wred_set: Queue settings port: %d cosq: %d rate: %d start_index: %d end_index:%d\n"), 7696 port, cosq, rate, start_index, end_index)); 7697 7698 for (pipe = from_pipe; pipe <= to_pipe; pipe++ ) { 7699 /* Config MMU_WRED_CONFIGm for the respective resource */ 7700 7701 for (i=0; i < _BCM_TH3_NUM_WRED_PROFILES; i++) { 7702 mems[i] = INVALIDm; 7703 } 7704 7705 if (wred_flags & (BCM_COSQ_DISCARD_COLOR_ALL | 7706 BCM_COSQ_DISCARD_TCP | 7707 BCM_COSQ_DISCARD_NONTCP | 7708 BCM_COSQ_DISCARD_ECT_MARKED | 7709 BCM_COSQ_DISCARD_RESPONSIVE_DROP | 7710 BCM_COSQ_DISCARD_NON_RESPONSIVE_DROP)) { 7711 need_profile = 1; 7712 LOG_INFO(BSL_LS_BCM_COSQ, 7713 (BSL_META_U(unit, "_bcm_th3_cosq_wred_set: Queue settings port: %d cosq: %d need_profile: %d\n"), 7714 port, cosq, need_profile)); 7715 7716 if (!(flags & (BCM_COSQ_DISCARD_COLOR_GREEN | 7717 BCM_COSQ_DISCARD_COLOR_YELLOW | 7718 BCM_COSQ_DISCARD_COLOR_RED))) { 7719 flags |= BCM_COSQ_DISCARD_COLOR_ALL; 7720 } 7721 7722 if (!(wred_flags & (BCM_COSQ_DISCARD_NONTCP | 7723 BCM_COSQ_DISCARD_NON_RESPONSIVE_DROP | 7724 BCM_COSQ_DISCARD_ECT_MARKED)) || 7725 ((wred_flags & BCM_COSQ_DISCARD_TCP) || 7726 (wred_flags & BCM_COSQ_DISCARD_RESPONSIVE_DROP))) { 7727 if (flags & BCM_COSQ_DISCARD_COLOR_GREEN) { 7728 mems[0] = wred_mems[0]; 7729 } 7730 if (flags & BCM_COSQ_DISCARD_COLOR_YELLOW) { 7731 mems[1] = wred_mems[1]; 7732 } 7733 if (flags & BCM_COSQ_DISCARD_COLOR_RED) { 7734 mems[2] = wred_mems[2]; 7735 } 7736 } 7737 if ((wred_flags & BCM_COSQ_DISCARD_NONTCP) || 7738 (wred_flags & BCM_COSQ_DISCARD_NON_RESPONSIVE_DROP)){ 7739 if (flags & BCM_COSQ_DISCARD_COLOR_GREEN) { 7740 mems[3] = wred_mems[3]; 7741 } 7742 if (flags & BCM_COSQ_DISCARD_COLOR_YELLOW) { 7743 mems[4] = wred_mems[4]; 7744 } 7745 if (flags & BCM_COSQ_DISCARD_COLOR_RED) { 7746 mems[5] = wred_mems[5]; 7747 } 7748 } 7749 if (wred_flags & BCM_COSQ_DISCARD_ECT_MARKED) { 7750 if (flags & BCM_COSQ_DISCARD_COLOR_GREEN) { 7751 mems[6] = wred_mems[6]; 7752 } 7753 if (flags & BCM_COSQ_DISCARD_COLOR_YELLOW) { 7754 mems[7] = wred_mems[7]; 7755 } 7756 if (flags & BCM_COSQ_DISCARD_COLOR_RED) { 7757 mems[8] = wred_mems[8]; 7758 } 7759 } 7760 } 7761 7762 entries[0] = &entry_tcp_green; 7763 entries[1] = &entry_tcp_yellow; 7764 entries[2] = &entry_tcp_red; 7765 entries[3] = &entry_nontcp_green; 7766 entries[4] = &entry_nontcp_yellow; 7767 entries[5] = &entry_nontcp_red; 7768 entries[6] = &entry_ecn_green; 7769 entries[7] = &entry_ecn_yellow; 7770 entries[8] = &entry_ecn_red; 7771 7772 if (buffer == BCM_COSQ_BUFFER_ID_INVALID) { 7773 itm_map = 3; 7774 } else { 7775 itm_map = (1 << buffer); 7776 } 7777 7778 for (itm = 0; itm < NUM_ITM(unit); itm ++) { 7779 if (!(itm_map & (1 << itm))) { 7780 continue; 7781 } 7782 7783 accessed = 1; 7784 for (index = start_index; index <= end_index; index++) { 7785 old_profile_index = TH3_WRED_PROFILE_INDEX_INVALID; 7786 if (portsp_setting || queue_setting) { 7787 BCM_IF_ERROR_RETURN 7788 (soc_tomahawk3_itm_mem_read(unit, wred_config_mem, itm, pipe, 7789 MEM_BLOCK_ALL, index, &entry)); 7790 } else { /* device_setting */ 7791 BCM_IF_ERROR_RETURN 7792 (soc_tomahawk3_itm_reg32_get(unit, wred_config_reg, -1, -1, 7793 index, &entry)); 7794 } 7795 if (need_profile) { 7796 if (portsp_setting || queue_setting) { 7797 old_profile_index = soc_mem_field32_get(unit, wred_config_mem, 7798 &entry, PROFILE_INDEXf); 7799 } else { /* device_setting */ 7800 old_profile_index = soc_reg_field_get(unit, wred_config_reg, 7801 entry, PROFILE_INDEXf); 7802 } 7803 LOG_INFO(BSL_LS_BCM_COSQ, 7804 (BSL_META_U(unit, "_bcm_th3_cosq_wred_set: Queue settings port: %d cosq: %d old_profile_index: %d\n"), 7805 port, cosq, old_profile_index)); 7806 7807 BCM_IF_ERROR_RETURN 7808 (soc_profile_mem_get(unit, _bcm_th3_wred_profile[unit], 7809 old_profile_index, 1, entries)); 7810 LOG_INFO(BSL_LS_BCM_COSQ, 7811 (BSL_META_U(unit, "_bcm_th3_cosq_wred_set: Queue settings port: %d cosq: %d 1\n"), 7812 port, cosq)); 7813 7814 for (i = 0; i < _BCM_TH3_NUM_WRED_PROFILES; i++) { 7815 if (mems[i] == INVALIDm) { 7816 continue; 7817 } 7818 soc_mem_field32_set(unit, wred_mems[i], entries[i], 7819 MIN_THDf, min_thresh); 7820 soc_mem_field32_set(unit, wred_mems[i], entries[i], 7821 MAX_THDf, max_thresh); 7822 soc_mem_field32_set(unit, wred_mems[i], entries[i], 7823 MAX_DROP_RATEf, rate); 7824 } 7825 BCM_IF_ERROR_RETURN 7826 (soc_profile_mem_add(unit, _bcm_th3_wred_profile[unit], 7827 entries, 1, &profile_index)); 7828 7829 LOG_INFO(BSL_LS_BCM_COSQ, 7830 (BSL_META_U(unit, "_bcm_th3_cosq_wred_set: Queue settings port: %d cosq: %d profile_index: %d\n"), 7831 port, cosq, profile_index)); 7832 if (portsp_setting || queue_setting) { 7833 soc_mem_field32_set(unit, wred_config_mem, &entry, PROFILE_INDEXf, profile_index); 7834 } else { /* device_setting */ 7835 soc_reg_field_set(unit, wred_config_reg, &entry, PROFILE_INDEXf, profile_index); 7836 } 7837 } 7838 7839 if (queue_setting) { 7840 /* Determine SPID */ 7841 int spid; 7842 if (cosq == -1) { 7843 BCM_IF_ERROR_RETURN 7844 (_bcm_th3_cosq_index_resolve(unit, port, index - start_index, 7845 _BCM_TH3_COSQ_INDEX_STYLE_EGR_POOL, 7846 NULL, &spid, &count)); 7847 } else { 7848 BCM_IF_ERROR_RETURN 7849 (_bcm_th3_cosq_index_resolve(unit, port, cosq, 7850 _BCM_TH3_COSQ_INDEX_STYLE_EGR_POOL, 7851 NULL, &spid, &count)); 7852 } 7853 LOG_INFO(BSL_LS_BCM_COSQ, 7854 (BSL_META_U(unit, "_bcm_th3_cosq_wred_set: Queue settings port: %d cosq: %d spid: %d\n"), 7855 port, cosq, spid)); 7856 soc_mem_field32_set(unit, wred_config_mem, &entry, SPIDf, spid); 7857 } 7858 7859 7860 if (portsp_setting || queue_setting) { 7861 soc_mem_field32_set(unit, wred_config_mem, &entry, WEIGHTf, gain); 7862 } else { /* device_setting */ 7863 soc_reg_field_set(unit, wred_config_reg, &entry, WEIGHTf, gain); 7864 } 7865 7866 /* Some APIs only modify profiles */ 7867 if (!ignore_enable_flags) { 7868 if (portsp_setting || queue_setting) { 7869 soc_mem_field32_set(unit, wred_config_mem, &entry, CAP_AVERAGEf, 7870 flags & BCM_COSQ_DISCARD_CAP_AVERAGE ? 1 : 0); 7871 soc_mem_field32_set(unit, wred_config_mem, &entry, WRED_ENf, 7872 flags & BCM_COSQ_DISCARD_ENABLE ? 1 : 0); 7873 } else { /* device_setting */ 7874 soc_reg_field_set(unit, wred_config_reg, &entry, CAP_AVERAGEf, 7875 flags & BCM_COSQ_DISCARD_CAP_AVERAGE ? 1 : 0); 7876 soc_reg_field_set(unit, wred_config_reg, &entry, WRED_ENf, 7877 flags & BCM_COSQ_DISCARD_ENABLE ? 1 : 0); 7878 } 7879 if (queue_setting) { 7880 soc_mem_field32_set(unit, wred_config_mem, &entry, ECN_MARKING_ENf, 7881 flags & BCM_COSQ_DISCARD_MARK_CONGESTION ? 1 : 0); 7882 } 7883 } 7884 7885 if (portsp_setting || queue_setting) { 7886 current_time_sel = soc_mem_field32_get(unit, wred_config_mem, 7887 &entry, TIME_DOMAIN_SELf); 7888 } else { /* device_setting */ 7889 current_time_sel = soc_reg_field_get(unit, wred_config_reg, 7890 entry, TIME_DOMAIN_SELf); 7891 } 7892 time = refresh_time - 1; 7893 exists = 0; 7894 /* If the time value exist, update reference count only */ 7895 for (time_id = 0; time_id < _BCM_TH3_NUM_TIME_DOMAIN; time_id++) { 7896 BCM_IF_ERROR_RETURN 7897 (_bcm_th3_cosq_time_domain_get(unit, time_id, &old_time)); 7898 if (time == old_time) { 7899 /* Only set exist flag if this entry reference count already update, 7900 otherwise update reference count */ 7901 if(time_id != current_time_sel){ 7902 if (portsp_setting || queue_setting) { 7903 soc_mem_field32_set(unit, wred_config_mem, &entry, 7904 TIME_DOMAIN_SELf, time_id); 7905 } else { /* device_setting */ 7906 soc_reg_field_set(unit, wred_config_reg, &entry, 7907 TIME_DOMAIN_SELf, time_id); 7908 } 7909 th3_time_domain_info[unit][time_id].ref_count++; 7910 th3_time_domain_info[unit][current_time_sel].ref_count--; 7911 } 7912 exists = 1; 7913 break; 7914 } 7915 } 7916 7917 if(!exists){ 7918 rv = _bcm_th3_cosq_time_domain_set(unit, time, &time_id); 7919 if(rv == SOC_E_NONE){ 7920 if (portsp_setting || queue_setting) { 7921 soc_mem_field32_set(unit, wred_config_mem, &entry, 7922 TIME_DOMAIN_SELf, time_id); 7923 } else { /* device_setting */ 7924 soc_reg_field_set(unit, wred_config_reg, &entry, 7925 TIME_DOMAIN_SELf, time_id); 7926 } 7927 th3_time_domain_info[unit][current_time_sel].ref_count--; 7928 } else { 7929 return rv; 7930 } 7931 } 7932 7933 if (flags & BCM_COSQ_DISCARD_MARK_CONGESTION) { 7934 if (queue_setting) { 7935 soc_mem_field32_set(unit, wred_config_mem, &entry, 7936 WRED_CONG_NOTIFICATION_RESOLUTION_TABLE_MARKING_INDEXf, 7937 resolution_id); 7938 } 7939 } else { 7940 if (queue_setting) { 7941 soc_mem_field32_set(unit, wred_config_mem, &entry, 7942 WRED_CONG_NOTIFICATION_RESOLUTION_TABLE_DROPPING_INDEXf, 7943 resolution_id); 7944 } 7945 } 7946 7947 if (portsp_setting || queue_setting) { 7948 BCM_IF_ERROR_RETURN 7949 (soc_tomahawk3_itm_mem_write(unit, wred_config_mem, itm, pipe, 7950 MEM_BLOCK_ALL, index, &entry)); 7951 } else { /* device_setting */ 7952 BCM_IF_ERROR_RETURN 7953 (soc_tomahawk3_itm_reg32_set(unit, wred_config_reg, itm, -1, 7954 index, entry)); 7955 } 7956 7957 if (old_profile_index != TH3_WRED_PROFILE_INDEX_INVALID) { 7958 SOC_IF_ERROR_RETURN 7959 (soc_profile_mem_delete(unit, _bcm_th3_wred_profile[unit], 7960 old_profile_index)); 7961 } 7962 7963 } 7964 } 7965 } 7966 7967 /* pipe (port) and itm (buffer) are not related */ 7968 if (!accessed) { 7969 return BCM_E_PARAM; 7970 } 7971 7972 if (device_setting) { 7973 flags &= ~(BCM_COSQ_DISCARD_DEVICE); 7974 PBMP_PORT_ITER(unit, port_num) { 7975 LOG_INFO(BSL_LS_BCM_COSQ, 7976 (BSL_META_U(unit, "_bcm_th3_cosq_wred_set: device_setting calling wred_queue with port: %d cosq: -1\n"), 7977 port_num)); 7978 BCM_IF_ERROR_RETURN 7979 (_bcm_th3_cosq_wred_set(unit, port_num, -1, buffer, 7980 flags, min_thresh, max_thresh, 7981 drop_probability, gain, 7982 FALSE, flags, refresh_time, 7983 resolution_id)); 7984 } 7985 } 7986 if (portsp_setting) { 7987 LOG_INFO(BSL_LS_BCM_COSQ, 7988 (BSL_META_U(unit, "_bcm_th3_cosq_wred_set: portsp_setting calling wred_queue with port: %d cosq: -1\n"), 7989 port)); 7990 flags &= ~(BCM_COSQ_DISCARD_PORT); 7991 BCM_IF_ERROR_RETURN 7992 (_bcm_th3_cosq_wred_set(unit, port, -1, buffer, 7993 flags, min_thresh, max_thresh, 7994 drop_probability, gain, 7995 FALSE, flags, refresh_time, 7996 resolution_id)); 7997 } 7998 7999 return rv; 8000 } 8001 8002 /* 8003 * Function: 8004 * _bcm_th3_cosq_wred_get 8005 * Purpose: 8006 * Configure unicast queue WRED setting 8007 * Parameters: 8008 * unit - (IN) unit number 8009 * port - (IN) port number or GPORT identifier 8010 * cosq - (IN) COS queue number 8011 * flags - (IN/OUT) BCM_COSQ_DISCARD_XXX 8012 * min_thresh - (OUT) Min Threshold 8013 * max_thresh - (OUT) Max Threshold 8014 * drop_probablity - (OUT) Probabilistic drop rate 8015 * gain - (OUT) 8016 * lflags - (IN) Config flags 8017 * refresh_time - (OUT) Time Domain 8018 * Returns: 8019 * BCM_E_XXX 8020 * Notes: 8021 * If port is any form of local port, cosq is the hardware queue index. 8022 */ 8023 STATIC int 8024 _bcm_th3_cosq_wred_get(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 8025 bcm_cosq_buffer_id_t buffer, 8026 uint32 *flags, uint32 *min_thresh, uint32 *max_thresh, 8027 int *drop_probability, int *gain, uint32 lflags, 8028 int *refresh_time, uint32 *resolution_id) 8029 { 8030 soc_mem_t wred_config_mem = INVALIDm, mem = INVALIDm; 8031 soc_reg_t wred_config_reg = INVALIDr; 8032 bcm_port_t local_port = -1; 8033 mmu_wred_drop_curve_profile_0_entry_t entry_tcp_green; 8034 mmu_wred_drop_curve_profile_1_entry_t entry_tcp_yellow; 8035 mmu_wred_drop_curve_profile_2_entry_t entry_tcp_red; 8036 mmu_wred_drop_curve_profile_3_entry_t entry_nontcp_green; 8037 mmu_wred_drop_curve_profile_4_entry_t entry_nontcp_yellow; 8038 mmu_wred_drop_curve_profile_5_entry_t entry_nontcp_red; 8039 mmu_wred_drop_curve_profile_6_entry_t entry_ecn_green; 8040 mmu_wred_drop_curve_profile_7_entry_t entry_ecn_yellow; 8041 mmu_wred_drop_curve_profile_8_entry_t entry_ecn_red; 8042 void *entries[_BCM_TH3_NUM_WRED_PROFILES]; 8043 void *entry_p; 8044 int index, profile_index; 8045 uint32 entry = 0; 8046 uint32 wred_flags = 0; 8047 int rate = 0, pipe = -1, itm; 8048 int time_id, time; 8049 int portsp_setting = 0; 8050 int queue_setting = 0; 8051 8052 if ((buffer != BCM_COSQ_BUFFER_ID_INVALID) && 8053 ((buffer < 0) || (buffer >= NUM_ITM(unit)))) { 8054 return BCM_E_PARAM; 8055 } 8056 8057 if (flags) { 8058 wred_flags = *flags | lflags; 8059 } else { 8060 wred_flags = lflags; 8061 } 8062 8063 if ((wred_flags & BCM_COSQ_DISCARD_DEVICE) && (port == BCM_GPORT_INVALID)) { 8064 /* (Port == -1) For all Global SPs */ 8065 index = 0; 8066 pipe = 0; 8067 wred_config_reg = MMU_WRED_POOL_CONFIGr; 8068 } else { 8069 BCM_IF_ERROR_RETURN 8070 (_bcm_th3_cosq_localport_resolve(unit, port, &local_port)); 8071 SOC_IF_ERROR_RETURN(soc_port_pipe_get(unit, local_port, &pipe)); 8072 8073 /* Check Flags for WRED res level - Device-SP/Port-SP/Queues */ 8074 if(wred_flags & BCM_COSQ_DISCARD_DEVICE) { 8075 wred_config_reg = MMU_WRED_POOL_CONFIGr; 8076 BCM_IF_ERROR_RETURN 8077 (_bcm_th3_cosq_index_resolve(unit, port, cosq, 8078 _BCM_TH3_COSQ_INDEX_STYLE_WRED_DEVICE, 8079 NULL, &index, NULL)); 8080 } else if (wred_flags & BCM_COSQ_DISCARD_PORT) { 8081 /* Port SP - Given or all SPs of the port */ 8082 wred_config_mem = MMU_WRED_PORTSP_CONFIGm; 8083 portsp_setting = 1; 8084 BCM_IF_ERROR_RETURN 8085 (_bcm_th3_cosq_index_resolve(unit, port, cosq, 8086 _BCM_TH3_COSQ_INDEX_STYLE_WRED_PORT, 8087 NULL, &index, NULL)); 8088 } else { 8089 /* Per Queue WRED settings */ 8090 wred_config_mem = MMU_WRED_QUEUE_CONFIGm; 8091 queue_setting = 1; 8092 BCM_IF_ERROR_RETURN 8093 (_bcm_th3_cosq_index_resolve(unit, port, cosq, 8094 _BCM_TH3_COSQ_INDEX_STYLE_WRED_QUEUE, 8095 NULL, &index, NULL)); 8096 } 8097 } 8098 8099 if ((index < 0) || (pipe == -1)) { 8100 return BCM_E_PARAM; 8101 } 8102 8103 if (buffer == BCM_COSQ_BUFFER_ID_INVALID) { 8104 itm = -1; 8105 } else if (port == BCM_GPORT_INVALID) { 8106 itm = buffer; 8107 pipe = -1; 8108 } else { 8109 itm = buffer; 8110 } 8111 8112 if (portsp_setting || queue_setting) { 8113 BCM_IF_ERROR_RETURN 8114 (soc_tomahawk3_itm_mem_read(unit, wred_config_mem, itm, pipe, 8115 MEM_BLOCK_ALL, index, &entry)); 8116 profile_index = soc_mem_field32_get(unit, wred_config_mem, 8117 &entry, PROFILE_INDEXf); 8118 } else { /* device_setting */ 8119 BCM_IF_ERROR_RETURN 8120 (soc_tomahawk3_itm_reg32_get(unit, wred_config_reg, itm, -1, 8121 index, &entry)); 8122 profile_index = soc_reg_field_get(unit, wred_config_reg, 8123 entry, PROFILE_INDEXf); 8124 } 8125 8126 8127 if (!(wred_flags & (BCM_COSQ_DISCARD_NONTCP | 8128 BCM_COSQ_DISCARD_NON_RESPONSIVE_DROP | 8129 BCM_COSQ_DISCARD_ECT_MARKED))) { 8130 /* By default we will assume 8131 BCM_COSQ_DISCARD_TCP */ 8132 if (wred_flags & BCM_COSQ_DISCARD_COLOR_YELLOW) { 8133 mem = MMU_WRED_DROP_CURVE_PROFILE_1_0m; 8134 entry_p = &entry_tcp_yellow; 8135 } else if (wred_flags & BCM_COSQ_DISCARD_COLOR_RED) { 8136 mem = MMU_WRED_DROP_CURVE_PROFILE_2_0m; 8137 entry_p = &entry_tcp_red; 8138 } else { 8139 /* By default we will assume 8140 BCM_COSQ_DISCARD_COLOR_GREEN */ 8141 mem = MMU_WRED_DROP_CURVE_PROFILE_0_0m; 8142 entry_p = &entry_tcp_green; 8143 } 8144 } else if ((wred_flags & BCM_COSQ_DISCARD_NONTCP) || 8145 (wred_flags & BCM_COSQ_DISCARD_NON_RESPONSIVE_DROP)) { 8146 if (wred_flags & BCM_COSQ_DISCARD_COLOR_YELLOW) { 8147 mem = MMU_WRED_DROP_CURVE_PROFILE_4_0m; 8148 entry_p = &entry_nontcp_yellow; 8149 } else if (wred_flags & BCM_COSQ_DISCARD_COLOR_RED) { 8150 mem = MMU_WRED_DROP_CURVE_PROFILE_5_0m; 8151 entry_p = &entry_nontcp_red; 8152 } else { 8153 /* By default we will assume 8154 BCM_COSQ_DISCARD_COLOR_GREEN */ 8155 mem = MMU_WRED_DROP_CURVE_PROFILE_3_0m; 8156 entry_p = &entry_nontcp_green; 8157 } 8158 } else { 8159 if (wred_flags & BCM_COSQ_DISCARD_COLOR_YELLOW) { 8160 mem = MMU_WRED_DROP_CURVE_PROFILE_7_0m; 8161 entry_p = &entry_ecn_yellow; 8162 } else if (wred_flags & BCM_COSQ_DISCARD_COLOR_RED) { 8163 mem = MMU_WRED_DROP_CURVE_PROFILE_8_0m; 8164 entry_p = &entry_ecn_red; 8165 } else { 8166 /* By default we will assume 8167 BCM_COSQ_DISCARD_COLOR_GREEN */ 8168 mem = MMU_WRED_DROP_CURVE_PROFILE_6_0m; 8169 entry_p = &entry_ecn_green; 8170 } 8171 } 8172 8173 entries[0] = &entry_tcp_green; 8174 entries[1] = &entry_tcp_yellow; 8175 entries[2] = &entry_tcp_red; 8176 entries[3] = &entry_nontcp_green; 8177 entries[4] = &entry_nontcp_yellow; 8178 entries[5] = &entry_nontcp_red; 8179 entries[6] = &entry_ecn_green; 8180 entries[7] = &entry_ecn_yellow; 8181 entries[8] = &entry_ecn_red; 8182 8183 BCM_IF_ERROR_RETURN 8184 (soc_profile_mem_get(unit, _bcm_th3_wred_profile[unit], 8185 profile_index, 1, entries)); 8186 if (min_thresh != NULL) { 8187 *min_thresh = soc_mem_field32_get(unit, mem, entry_p, MIN_THDf); 8188 } 8189 if (max_thresh != NULL) { 8190 *max_thresh = soc_mem_field32_get(unit, mem, entry_p, MAX_THDf); 8191 } 8192 if (drop_probability != NULL) { 8193 rate = soc_mem_field32_get(unit, mem, entry_p, MAX_DROP_RATEf); 8194 *drop_probability = _bcm_th3_drop_prob_to_percent(rate); 8195 } 8196 if (gain) { 8197 if (portsp_setting || queue_setting) { 8198 *gain = soc_mem_field32_get(unit, wred_config_mem, &entry, WEIGHTf); 8199 } else { /* device_setting */ 8200 *gain = soc_reg_field_get(unit, wred_config_reg, entry, WEIGHTf); 8201 } 8202 } 8203 8204 /* Get the Time Domain value */ 8205 if (refresh_time) { 8206 if (portsp_setting || queue_setting) { 8207 time_id = soc_mem_field32_get(unit, wred_config_mem, &entry, 8208 TIME_DOMAIN_SELf); 8209 } else { /* device_setting */ 8210 time_id = soc_reg_field_get(unit, wred_config_reg, entry, 8211 TIME_DOMAIN_SELf); 8212 } 8213 BCM_IF_ERROR_RETURN 8214 (_bcm_th3_cosq_time_domain_get(unit,time_id,&time)); 8215 *refresh_time = time + 1; 8216 } 8217 8218 /* Get flags */ 8219 if (flags) { 8220 *flags &= ~(BCM_COSQ_DISCARD_CAP_AVERAGE | BCM_COSQ_DISCARD_ENABLE | 8221 BCM_COSQ_DISCARD_MARK_CONGESTION); 8222 if (portsp_setting || queue_setting) { 8223 if (soc_mem_field32_get(unit, wred_config_mem, &entry, CAP_AVERAGEf)) { 8224 *flags |= BCM_COSQ_DISCARD_CAP_AVERAGE; 8225 } 8226 if (soc_mem_field32_get(unit, wred_config_mem, &entry, WRED_ENf)) { 8227 *flags |= BCM_COSQ_DISCARD_ENABLE; 8228 } 8229 } else { /* device_setting */ 8230 if (soc_reg_field_get(unit, wred_config_reg, entry, CAP_AVERAGEf)) { 8231 *flags |= BCM_COSQ_DISCARD_CAP_AVERAGE; 8232 } 8233 if (soc_reg_field_get(unit, wred_config_reg, entry, WRED_ENf)) { 8234 *flags |= BCM_COSQ_DISCARD_ENABLE; 8235 } 8236 } 8237 if (queue_setting) { 8238 if (soc_mem_field32_get(unit, wred_config_mem, &entry, ECN_MARKING_ENf)) { 8239 *flags |= BCM_COSQ_DISCARD_MARK_CONGESTION; 8240 } 8241 } 8242 } 8243 8244 /* Get resolution table index */ 8245 if (resolution_id) { 8246 if (queue_setting) { 8247 if (soc_mem_field32_get(unit, wred_config_mem, &entry, ECN_MARKING_ENf)) { 8248 *resolution_id = soc_mem_field32_get(unit, wred_config_mem, &entry, 8249 WRED_CONG_NOTIFICATION_RESOLUTION_TABLE_MARKING_INDEXf); 8250 } else { 8251 *resolution_id = soc_mem_field32_get(unit, wred_config_mem, &entry, 8252 WRED_CONG_NOTIFICATION_RESOLUTION_TABLE_DROPPING_INDEXf); 8253 } 8254 } 8255 } 8256 8257 return BCM_E_NONE; 8258 } 8259 8260 8261 8262 /* 8263 * Function: 8264 * bcm_th3_cosq_discard_set 8265 * Purpose: 8266 * Get COS queue bandwidth control configuration 8267 * Parameters: 8268 * unit - (IN) unit number 8269 * flags - (IN) DISCARD flags 8270 * Returns: 8271 * BCM_E_XXX 8272 * Notes: 8273 * Set the WRED discard flags 8274 */ 8275 8276 int 8277 bcm_th3_cosq_discard_set(int unit, uint32 flags) 8278 { 8279 bcm_port_t port; 8280 8281 if (_bcm_th3_cosq_port_info[unit] == NULL) { 8282 return BCM_E_INIT; 8283 } 8284 8285 if (flags & ~(BCM_COSQ_DISCARD_DEVICE | 8286 BCM_COSQ_DISCARD_NONTCP | 8287 BCM_COSQ_DISCARD_COLOR_ALL | 8288 BCM_COSQ_DISCARD_PORT | 8289 BCM_COSQ_DISCARD_TCP | 8290 BCM_COSQ_DISCARD_COLOR_GREEN | 8291 BCM_COSQ_DISCARD_COLOR_YELLOW | 8292 BCM_COSQ_DISCARD_COLOR_RED | 8293 BCM_COSQ_DISCARD_CAP_AVERAGE | 8294 BCM_COSQ_DISCARD_ENABLE | 8295 BCM_COSQ_DISCARD_MARK_CONGESTION)) { 8296 return BCM_E_PARAM; 8297 } 8298 8299 flags &= ~(BCM_COSQ_DISCARD_NONTCP | BCM_COSQ_DISCARD_COLOR_ALL); 8300 8301 PBMP_PORT_ITER(unit, port) { 8302 /* cosq(0), buffer(INVALID), flags, min_thresh(0) 8303 max_thresh(0), drop_prob(0), gain(0), ignore_enable_flags(0), 8304 lflags(BCM_COSQ_DISCARD_PORT), refresh_time(1), resolution_id(0) */ 8305 BCM_IF_ERROR_RETURN 8306 (_bcm_th3_cosq_wred_set(unit, port, 0, BCM_COSQ_BUFFER_ID_INVALID, 8307 flags, 0, 0, 0, 0, 8308 FALSE, BCM_COSQ_DISCARD_PORT, 1, 0)); 8309 } 8310 8311 return BCM_E_NONE; 8312 } 8313 8314 /* 8315 * Function: 8316 * bcm_th3_cosq_discard_get 8317 * Purpose: 8318 * Get COS queue bandwidth control configuration 8319 * Parameters: 8320 * unit - (IN) unit number 8321 * flags - (OUT) DISCARD flags 8322 * Returns: 8323 * BCM_E_XXX 8324 * Notes: 8325 * Get the WRED discard flags 8326 */ 8327 8328 int 8329 bcm_th3_cosq_discard_get(int unit, uint32 *flags) 8330 { 8331 bcm_port_t port; 8332 8333 PBMP_PORT_ITER(unit, port) { 8334 *flags = 0; 8335 /* use setting from hardware cosq index 0 of the first port */ 8336 return _bcm_th3_cosq_wred_get(unit, port, 0, BCM_COSQ_BUFFER_ID_INVALID, 8337 flags, NULL, NULL, NULL, 8338 NULL, BCM_COSQ_DISCARD_PORT, NULL, NULL); 8339 } 8340 8341 return BCM_E_NOT_FOUND; 8342 } 8343 8344 /* 8345 * Function: 8346 * bcm_th3_cosq_discard_port_set 8347 * Purpose: 8348 * Configure port WRED setting 8349 * Parameters: 8350 * unit - (IN) unit number 8351 * port - (IN) port number or GPORT identifier 8352 * cosq - (IN) COS queue number 8353 * color - (IN) 8354 * drop_start - (IN) 8355 * drop_slot - (IN) 8356 * average_time - (IN) 8357 * Returns: 8358 * BCM_E_XXX 8359 * Notes: 8360 * If port is any form of local port, cosq is the hardware queue index. 8361 * Same as TD2 except for Reg changes. 8362 */ 8363 int 8364 bcm_th3_cosq_discard_port_set(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 8365 uint32 color, int drop_start, int drop_slope, 8366 int average_time) 8367 { 8368 bcm_port_t local_port; 8369 bcm_pbmp_t pbmp; 8370 int gain; 8371 uint32 min_thresh, max_thresh, shared_limit, itm_map; 8372 uint32 bits, flags = 0; 8373 8374 if (drop_start < 0 || drop_start > 100 || 8375 drop_slope < 0 || drop_slope > 90) { 8376 return BCM_E_PARAM; 8377 } 8378 8379 /* 8380 * average queue size is reculated every 1us, the formula is 8381 * avg_qsize(t + 1) = 8382 * avg_qsize(t) + (cur_qsize - avg_qsize(t)) / (2 ** gain) 8383 * gain = log2(average_time) 8384 */ 8385 bits = average_time & 0xffff; 8386 if (bits != 0) { 8387 bits |= bits >> 1; 8388 bits |= bits >> 2; 8389 bits |= bits >> 4; 8390 bits |= bits >> 8; 8391 gain = _shr_popcount(bits) - 1; 8392 } else { 8393 gain = 0; 8394 } 8395 8396 /* 8397 * per-port cell limit may be disabled. 8398 * per-port per-cos cell limit may be set to use dynamic method. 8399 * therefore drop_start percentage is based on per-device total shared 8400 * cells. 8401 */ 8402 itm_map = SOC_INFO(unit).itm_map; 8403 _TH3_ARRAY_MIN(_BCM_TH3_MMU_INFO(unit)->shared_limit, NUM_ITM(unit), 8404 itm_map, shared_limit); 8405 min_thresh = ((drop_start * shared_limit) + (100 - 1)) / 100; 8406 8407 /* Calculate the max threshold. For a given slope (angle in 8408 * degrees), determine how many packets are in the range from 8409 * 0% drop probability to 100% drop probability. Add that 8410 * number to the min_treshold to the the max_threshold. 8411 */ 8412 max_thresh = min_thresh + _bcm_th3_angle_to_cells(drop_slope); 8413 if (max_thresh > TH3_WRED_CELL_FIELD_MAX) { 8414 max_thresh = TH3_WRED_CELL_FIELD_MAX; 8415 } 8416 8417 if (BCM_GPORT_IS_SET(port)) { 8418 BCM_IF_ERROR_RETURN 8419 (_bcm_th3_cosq_wred_set(unit, port, cosq, 8420 BCM_COSQ_BUFFER_ID_INVALID, color, 8421 min_thresh, max_thresh, 100, gain, 8422 TRUE, flags, 1, 0)); 8423 } else { 8424 if (port == -1) { 8425 BCM_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit)); 8426 } else if (!SOC_PORT_VALID(unit, port)) { 8427 return BCM_E_PORT; 8428 } else { 8429 BCM_PBMP_PORT_SET(pbmp, port); 8430 } 8431 8432 BCM_PBMP_ITER(pbmp, local_port) { 8433 BCM_IF_ERROR_RETURN 8434 (_bcm_th3_cosq_wred_set(unit, local_port, cosq, 8435 BCM_COSQ_BUFFER_ID_INVALID, color, 8436 min_thresh, max_thresh, 100, gain, 8437 TRUE, 0, 1, 0)); 8438 } 8439 } 8440 8441 return BCM_E_NONE; 8442 } 8443 8444 /* 8445 * Function: 8446 * bcm_th3_cosq_discard_port_get 8447 * Purpose: 8448 * Get port WRED setting 8449 * Parameters: 8450 * unit - (IN) unit number 8451 * port - (IN) port number or GPORT identifier 8452 * cosq - (IN) COS queue number 8453 * color - (OUT) 8454 * drop_start - (OUT) 8455 * drop_slot - (OUT) 8456 * average_time - (OUT) 8457 * Returns: 8458 * BCM_E_XXX 8459 * Notes: 8460 * If port is any form of local port, cosq is the hardware queue index. 8461 * Same as TD2 except for Reg changes. 8462 */ 8463 int 8464 bcm_th3_cosq_discard_port_get(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 8465 uint32 color, int *drop_start, int *drop_slope, 8466 int *average_time) 8467 { 8468 bcm_port_t local_port; 8469 bcm_pbmp_t pbmp; 8470 int gain, drop_prob; 8471 uint32 min_thresh, max_thresh, shared_limit, itm_map; 8472 int refresh_time = 0; 8473 8474 if (drop_start == NULL || drop_slope == NULL || average_time == NULL) { 8475 return BCM_E_PARAM; 8476 } 8477 8478 if (BCM_GPORT_IS_SET(port)) { 8479 local_port = port; 8480 } else { 8481 if (port == -1) { 8482 BCM_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit)); 8483 } else if (!SOC_PORT_VALID(unit, port)) { 8484 return BCM_E_PORT; 8485 } else { 8486 BCM_PBMP_PORT_SET(pbmp, port); 8487 } 8488 BCM_PBMP_ITER(pbmp, local_port) { 8489 break; 8490 } 8491 } 8492 8493 BCM_IF_ERROR_RETURN 8494 (_bcm_th3_cosq_wred_get(unit, local_port, cosq == -1 ? 0 : cosq, 8495 BCM_COSQ_BUFFER_ID_INVALID, 8496 &color, &min_thresh, &max_thresh, &drop_prob, 8497 &gain, 0, &refresh_time, NULL)); 8498 8499 /* 8500 * average queue size is reculated every 8us, the formula is 8501 * avg_qsize(t + 1) = 8502 * avg_qsize(t) + (cur_qsize - avg_qsize(t)) / (2 ** gain) 8503 */ 8504 *average_time = (1 << gain); 8505 8506 itm_map = SOC_INFO(unit).itm_map; 8507 _TH3_ARRAY_MIN(_BCM_TH3_MMU_INFO(unit)->shared_limit, NUM_ITM(unit), 8508 itm_map, shared_limit); 8509 8510 if (min_thresh > shared_limit) { 8511 min_thresh = shared_limit; 8512 } 8513 8514 if (max_thresh > shared_limit) { 8515 max_thresh = shared_limit; 8516 } 8517 8518 *drop_start = min_thresh * 100 / shared_limit; 8519 8520 /* Calculate the slope using the min and max threshold. 8521 * The angle is calculated knowing drop probability at min 8522 * threshold is 0% and drop probability at max threshold is 100%. 8523 */ 8524 *drop_slope = _bcm_th3_cells_to_angle(max_thresh - min_thresh); 8525 8526 return BCM_E_NONE; 8527 } 8528 8529 /* 8530 * Function: 8531 * bcm_th3_cosq_gport_discard_set 8532 * Purpose: 8533 * Configure port WRED setting 8534 * Parameters: 8535 * unit - (IN) unit number 8536 * port - (IN) GPORT identifier 8537 * cosq - (IN) COS queue to configure, -1 for all COS queues 8538 * buffer - (IN) ITM ID 8539 * discard - (IN) discard settings 8540 * Returns: 8541 * BCM_E_XXX 8542 */ 8543 int 8544 bcm_th3_cosq_gport_discard_set(int unit, bcm_gport_t gport, 8545 bcm_cos_queue_t cosq, 8546 bcm_cosq_buffer_id_t buffer, 8547 bcm_cosq_gport_discard_t *discard) 8548 { 8549 uint32 min_thresh, max_thresh, flags = 0; 8550 int cell_size, cell_field_max; 8551 bcm_port_t local_port = -1; 8552 8553 LOG_INFO(BSL_LS_BCM_COSQ, 8554 (BSL_META_U(unit, "bcm_th3_cosq_gport_discard_set: gport: %d cosq: %d buffer: %d \n"), 8555 gport, cosq, buffer)); 8556 /* Time Domain */ 8557 /* the reasonable range of refresh_time is from 1 to 64 */ 8558 if (discard == NULL || 8559 discard->gain < 0 || discard->gain > 15 || 8560 discard->drop_probability < 0 || discard->drop_probability > 100 || 8561 discard->profile_id > 3 || 8562 discard->refresh_time <= 0 || discard->refresh_time > 64) { 8563 LOG_INFO(BSL_LS_BCM_COSQ, 8564 (BSL_META_U(unit, "bcm_th3_cosq_gport_discard_set: Incorrect Parameter 1 gport: %d cosq: %d\n"), 8565 gport, cosq)); 8566 return BCM_E_PARAM; 8567 } 8568 8569 if (discard == NULL || 8570 discard->gain < 0 || discard->gain > 15 || 8571 discard->drop_probability < 0 || discard->drop_probability > 100 || 8572 (discard->min_thresh > discard->max_thresh) || 8573 (discard->min_thresh < 0)) { 8574 LOG_INFO(BSL_LS_BCM_COSQ, 8575 (BSL_META_U(unit, "bcm_th3_cosq_gport_discard_set: Incorrect Parameter 2 gport: %d cosq: %d\n"), 8576 gport, cosq)); 8577 return BCM_E_PARAM; 8578 } 8579 8580 cell_size = _TH3_MMU_BYTES_PER_CELL; 8581 cell_field_max = 0x7ffff; 8582 8583 min_thresh = discard->min_thresh; 8584 max_thresh = discard->max_thresh; 8585 if (discard->flags & BCM_COSQ_DISCARD_BYTES) { 8586 /* Convert bytes to cells */ 8587 min_thresh += (cell_size - 1); 8588 min_thresh /= cell_size; 8589 8590 max_thresh += (cell_size - 1); 8591 max_thresh /= cell_size; 8592 LOG_INFO(BSL_LS_BCM_COSQ, 8593 (BSL_META_U(unit, "bcm_th3_cosq_gport_discard_set: gport: %d cosq: %d min_thres: %d max_thresh: %d\n"), 8594 gport, cosq, min_thresh, max_thresh)); 8595 8596 if ((min_thresh > cell_field_max) || 8597 (max_thresh > cell_field_max)) { 8598 LOG_INFO(BSL_LS_BCM_COSQ, 8599 (BSL_META_U(unit, "bcm_th3_cosq_gport_discard_set: Incorrect Parameter 3 gport: %d cosq: %d\n"), 8600 gport, cosq)); 8601 return BCM_E_PARAM; 8602 } 8603 } else if (discard->flags & BCM_COSQ_DISCARD_PACKETS) { 8604 /* Packet mode not supported */ 8605 LOG_INFO(BSL_LS_BCM_COSQ, 8606 (BSL_META_U(unit, "bcm_th3_cosq_gport_discard_set: Incorrect Parameter 4 gport: %d cosq: %d\n"), 8607 gport, cosq)); 8608 return BCM_E_PARAM; 8609 } else { 8610 /* Lower layer function will update thresh when these flags are 8611 * configured, this interface only allow such opration when 8612 * BCM_COSQ_DISCARD_BYTES is also configured. 8613 */ 8614 if (discard->flags & (BCM_COSQ_DISCARD_COLOR_ALL | 8615 BCM_COSQ_DISCARD_TCP | 8616 BCM_COSQ_DISCARD_NONTCP | 8617 BCM_COSQ_DISCARD_ECT_MARKED | 8618 BCM_COSQ_DISCARD_RESPONSIVE_DROP | 8619 BCM_COSQ_DISCARD_NON_RESPONSIVE_DROP)) { 8620 LOG_INFO(BSL_LS_BCM_COSQ, 8621 (BSL_META_U(unit, "bcm_th3_cosq_gport_discard_set: Incorrect Parameter 5 gport: %d cosq: %d\n"), 8622 gport, cosq)); 8623 return BCM_E_PARAM; 8624 } 8625 } 8626 8627 if (gport != BCM_GPORT_INVALID) { 8628 BCM_IF_ERROR_RETURN 8629 (_bcm_th3_cosq_localport_resolve(unit, gport, &local_port)); 8630 if (IS_CPU_PORT(unit,local_port) || IS_LB_PORT(unit,local_port)) { 8631 LOG_INFO(BSL_LS_BCM_COSQ, 8632 (BSL_META_U(unit, "bcm_th3_cosq_gport_discard_set: Incorrect Parameter 6 gport: %d cosq: %d\n"), 8633 gport, cosq)); 8634 return BCM_E_PORT; 8635 } 8636 if ((cosq < -1) || (cosq >= _bcm_th3_get_num_ucq(unit))) { 8637 LOG_INFO(BSL_LS_BCM_COSQ, 8638 (BSL_META_U(unit, "bcm_th3_cosq_gport_discard_set: Incorrect Parameter 7 gport: %d cosq: %d\n"), 8639 gport, cosq)); 8640 return BCM_E_PARAM; 8641 } 8642 } 8643 8644 BCM_IF_ERROR_RETURN 8645 (_bcm_th3_cosq_wred_set(unit, gport, cosq, buffer, 8646 discard->flags, min_thresh, max_thresh, 8647 discard->drop_probability, discard->gain, 8648 FALSE, flags, discard->refresh_time, 8649 discard->profile_id)); 8650 8651 return BCM_E_NONE; 8652 } 8653 8654 /* 8655 * Function: 8656 * bcm_th3_cosq_gport_discard_get 8657 * Purpose: 8658 * Get port WRED setting 8659 * Parameters: 8660 * unit - (IN) unit number 8661 * port - (IN) GPORT identifier 8662 * cosq - (IN) COS queue to get, -1 for any queue 8663 * buffer - (IN) ITM ID 8664 * discard - (OUT) discard settings 8665 * Returns: 8666 * BCM_E_XXX 8667 */ 8668 int 8669 bcm_th3_cosq_gport_discard_get(int unit, bcm_gport_t gport, 8670 bcm_cos_queue_t cosq, 8671 bcm_cosq_buffer_id_t buffer, 8672 bcm_cosq_gport_discard_t *discard) 8673 { 8674 uint32 min_thresh, max_thresh; 8675 bcm_port_t local_port = -1; 8676 8677 if (discard == NULL) { 8678 return BCM_E_PARAM; 8679 } 8680 8681 if (discard->flags & BCM_COSQ_DISCARD_PACKETS) { 8682 /* Packet mode not supported */ 8683 return BCM_E_PARAM; 8684 } 8685 8686 if (gport != BCM_GPORT_INVALID) { 8687 BCM_IF_ERROR_RETURN 8688 (_bcm_th3_cosq_localport_resolve(unit, gport, &local_port)); 8689 if (IS_CPU_PORT(unit,local_port) || IS_LB_PORT(unit,local_port)) { 8690 return BCM_E_PORT; 8691 } 8692 if ((cosq < -1) || (cosq >= _BCM_TH3_COS_MAX)) { 8693 return BCM_E_PARAM; 8694 } 8695 } 8696 8697 BCM_IF_ERROR_RETURN 8698 (_bcm_th3_cosq_wred_get(unit, gport, cosq == -1 ? 0 : cosq, buffer, 8699 &discard->flags, &min_thresh, &max_thresh, 8700 &discard->drop_probability, &discard->gain, 8701 0, &discard->refresh_time, 8702 &discard->profile_id)); 8703 8704 /* Convert number of cells to number of bytes */ 8705 discard->min_thresh = min_thresh * _TH3_MMU_BYTES_PER_CELL; 8706 discard->max_thresh = max_thresh * _TH3_MMU_BYTES_PER_CELL; 8707 8708 return BCM_E_NONE; 8709 } 8710 8711 /* 8712 * Function: 8713 * bcm_th3_cosq_wred_resolution_id_create 8714 * Purpose: 8715 * Assign a unused entry. Default drop rules are WRED drop. 8716 * Parameters: 8717 * unit - (IN) unit number 8718 * index - (OUT) entry index 8719 * Returns: 8720 * BCM_E_XXX 8721 */ 8722 int 8723 bcm_th3_cosq_wred_resolution_entry_create(int unit, int *index) 8724 { 8725 uint32 i, rval = 0; 8726 soc_reg_t reg = MMU_WRED_CONG_NOTIFICATION_RESOLUTION_TABLEr; 8727 8728 for (i = 0; i < _BCM_TH3_NUM_WRED_RESOLUTION_TABLE; i++) { 8729 if (_bcm_th3_wred_resolution_tbl[i] == 0) { 8730 /* hw reset value */ 8731 soc_reg_field_set(unit, reg, &rval, MMU_CONGESTION_EXPERIENCEf, 0xAAA); 8732 BCM_IF_ERROR_RETURN(soc_reg32_set(unit, reg, REG_PORT_ANY, i, rval)); 8733 _bcm_th3_wred_resolution_tbl[i] ++; 8734 *index = i; 8735 return SOC_E_NONE; 8736 } 8737 } 8738 8739 return SOC_E_RESOURCE; 8740 } 8741 8742 /* 8743 * Function: 8744 * bcm_th3_cosq_wred_resolution_id_destroy 8745 * Purpose: 8746 * Callback an entry and set its drop rules to WRED drop. 8747 * Parameters: 8748 * unit - (IN) unit number 8749 * index - (IN) entry index 8750 * Returns: 8751 * BCM_E_XXX 8752 */ 8753 int 8754 bcm_th3_cosq_wred_resolution_entry_destroy(int unit, int index) 8755 { 8756 uint32 rval = 0; 8757 soc_reg_t reg = MMU_WRED_CONG_NOTIFICATION_RESOLUTION_TABLEr; 8758 8759 if ((index < 0) || (index >= _BCM_TH3_NUM_WRED_RESOLUTION_TABLE)) { 8760 return SOC_E_PARAM; 8761 } 8762 8763 if (_bcm_th3_wred_resolution_tbl[index] == 0) { 8764 return SOC_E_NOT_FOUND; 8765 } 8766 8767 /* hw reset value */ 8768 soc_reg_field_set(unit, reg, &rval, MMU_CONGESTION_EXPERIENCEf, 0xAAA); 8769 BCM_IF_ERROR_RETURN(soc_reg32_set(unit, reg, REG_PORT_ANY, index, rval)); 8770 _bcm_th3_wred_resolution_tbl[index] = 0; 8771 8772 return SOC_E_NONE; 8773 } 8774 8775 /* 8776 * Function: 8777 * bcm_th3_cosq_wred_resolution_set 8778 * Purpose: 8779 * Set one rule of a resolution table entry 8780 * Parameters: 8781 * unit - (IN) unit number 8782 * index - (IN) entry index 8783 * rule - (IN) drop rule 8784 * Returns: 8785 * BCM_E_XXX 8786 * Notes: 8787 * One entry has 12 bits, equals to 6 rules 8788 */ 8789 int 8790 bcm_th3_cosq_wred_resolution_set(int unit, int index, bcm_cosq_discard_rule_t *rule) 8791 { 8792 uint32 offset, sp, qmin; 8793 uint32 rval, fval, drop; 8794 soc_reg_t reg = MMU_WRED_CONG_NOTIFICATION_RESOLUTION_TABLEr; 8795 8796 if ((index < 0) || (index >= _BCM_TH3_NUM_WRED_RESOLUTION_TABLE)) { 8797 return SOC_E_PARAM; 8798 } 8799 8800 if (_bcm_th3_wred_resolution_tbl[index] == 0) { 8801 return BCM_E_NOT_FOUND; 8802 } 8803 8804 switch (rule->egress_pool_congestion_state) { 8805 case BCM_COSQ_DISCARD_CONGESTION_LOW: 8806 sp = 0; 8807 break; 8808 case BCM_COSQ_DISCARD_CONGESTION_MEDIUM: 8809 sp = 1; 8810 break; 8811 case BCM_COSQ_DISCARD_CONGESTION_HIGH: 8812 sp = 2; 8813 break; 8814 default: 8815 return SOC_E_PARAM; 8816 } 8817 switch (rule->queue_min_congestion_state) { 8818 case BCM_COSQ_DISCARD_CONGESTION_LOW: 8819 qmin = 0; 8820 break; 8821 case BCM_COSQ_DISCARD_CONGESTION_HIGH: 8822 qmin = 1; 8823 break; 8824 default: 8825 return SOC_E_PARAM; 8826 } 8827 8828 switch (rule->action) { 8829 case BCM_COSQ_DISCARD_ACTION_WRED_DROP: 8830 drop = 0x2; 8831 break; 8832 case BCM_COSQ_DISCARD_ACTION_FORCE_DROP: 8833 drop = 0x3; 8834 break; 8835 case BCM_COSQ_DISCARD_ACTION_FORCE_NO_DROP: 8836 drop = 0x0; 8837 break; 8838 default: 8839 return SOC_E_PARAM; 8840 } 8841 8842 BCM_IF_ERROR_RETURN(soc_reg32_get(unit, reg, REG_PORT_ANY, index, &rval)); 8843 fval = soc_reg_field_get(unit, reg, rval, MMU_CONGESTION_EXPERIENCEf); 8844 8845 offset = (sp * 2 + qmin) * 2; /* 2 bits per rule */ 8846 fval = (fval & (~(0x3 << offset))) | (drop << offset); 8847 8848 soc_reg_field_set(unit, reg, &rval, MMU_CONGESTION_EXPERIENCEf, fval); 8849 BCM_IF_ERROR_RETURN(soc_reg32_set(unit, reg, REG_PORT_ANY, index, rval)); 8850 8851 return SOC_E_NONE; 8852 } 8853 8854 /* 8855 * Function: 8856 * bcm_th3_cosq_wred_resolution_get 8857 * Purpose: 8858 * Get all rules of a resolution table entry 8859 * Parameters: 8860 * unit - (IN) unit number 8861 * index - (IN) entry index 8862 * max - (IN) rule array size 8863 * rule - (OUT) rule array 8864 * count - (OUT) actual rules count 8865 * Returns: 8866 * BCM_E_XXX 8867 * Notes: 8868 * One entry has 12 bits, equals to 6 rules 8869 */ 8870 int 8871 bcm_th3_cosq_wred_resolution_get(int unit, int index, int max, 8872 bcm_cosq_discard_rule_t *rule, int *count) 8873 { 8874 uint32 offset, sp, qmin, i = 0; 8875 uint32 rval, fval, action; 8876 soc_reg_t reg = MMU_WRED_CONG_NOTIFICATION_RESOLUTION_TABLEr; 8877 uint32 sp_map[3] = { 8878 BCM_COSQ_DISCARD_CONGESTION_LOW, 8879 BCM_COSQ_DISCARD_CONGESTION_MEDIUM, 8880 BCM_COSQ_DISCARD_CONGESTION_HIGH, 8881 }; 8882 uint32 qmin_map[2] = { 8883 BCM_COSQ_DISCARD_CONGESTION_LOW, 8884 BCM_COSQ_DISCARD_CONGESTION_HIGH, 8885 }; 8886 uint32 action_map[4] = { 8887 BCM_COSQ_DISCARD_ACTION_FORCE_NO_DROP, 8888 -1, 8889 BCM_COSQ_DISCARD_ACTION_WRED_DROP, 8890 BCM_COSQ_DISCARD_ACTION_FORCE_DROP, 8891 }; 8892 if ((!count) || 8893 (index < 0) || (index >= _BCM_TH3_NUM_WRED_RESOLUTION_TABLE)) { 8894 return SOC_E_PARAM; 8895 } 8896 8897 *count = 3 * 2; 8898 8899 if (!rule) { 8900 return SOC_E_NONE; 8901 } 8902 8903 BCM_IF_ERROR_RETURN(soc_reg32_get(unit, reg, REG_PORT_ANY, index, &rval)); 8904 fval = soc_reg_field_get(unit, reg, rval, MMU_CONGESTION_EXPERIENCEf); 8905 8906 for (sp = 0; sp < 3; sp ++) { 8907 for (qmin = 0; qmin < 2; qmin ++) { 8908 offset = (sp * 2 + qmin) * 2; /* 2 bits per rule */ 8909 action = (fval >> offset) & 0x3; 8910 if (i < max) { 8911 rule[i].egress_pool_congestion_state = sp_map[sp]; 8912 rule[i].queue_min_congestion_state = qmin_map[qmin]; 8913 rule[i].action = action_map[action]; 8914 i++; 8915 } 8916 } 8917 } 8918 8919 return SOC_E_NONE; 8920 } 8921 8922 /* Shaper APIs */ 8923 /* 8924 * Function: 8925 * bcm_th3_cosq_gport_bandwidth_get 8926 * Purpose: 8927 * Get COS queue bandwidth control configuration 8928 * Parameters: 8929 * unit - (IN) unit number 8930 * gport - (IN) GPORT identifier 8931 * cosq - (IN) COS queue to get, -1 for any COS queue 8932 * kbits_sec_min - (OUT) minimum bandwidth, kbits/sec 8933 * kbits_sec_max - (OUT) maximum bandwidth, kbits/sec 8934 * flags - (OUT) BCM_COSQ_BW_* 8935 * Returns: 8936 * BCM_E_XXX 8937 */ 8938 int 8939 bcm_th3_cosq_gport_bandwidth_get(int unit, bcm_gport_t gport, 8940 bcm_cos_queue_t cosq, uint32 *kbits_sec_min, 8941 uint32 *kbits_sec_max, uint32 *flags) 8942 { 8943 uint32 kbits_sec_burst; 8944 8945 BCM_IF_ERROR_RETURN 8946 (_bcm_th3_cosq_bucket_get(unit, gport, cosq, 8947 kbits_sec_min, kbits_sec_max, 8948 &kbits_sec_burst, &kbits_sec_burst, flags)); 8949 return BCM_E_NONE; 8950 } 8951 8952 /* 8953 * Function: 8954 * bcm_th3_cosq_gport_bandwidth_set 8955 * Purpose: 8956 * Configure COS queue bandwidth control 8957 * Parameters: 8958 * unit - (IN) unit number 8959 * gport - (IN) GPORT identifier 8960 * cosq - (IN) COS queue to configure, -1 for all COS queues 8961 * kbits_sec_min - (IN) minimum bandwidth, kbits/sec 8962 * kbits_sec_max - (IN) maximum bandwidth, kbits/sec 8963 * flags - (IN) BCM_COSQ_BW_* 8964 * Returns: 8965 * BCM_E_XXX 8966 */ 8967 int 8968 bcm_th3_cosq_gport_bandwidth_set(int unit, bcm_gport_t gport, 8969 bcm_cos_queue_t cosq, uint32 kbits_sec_min, 8970 uint32 kbits_sec_max, uint32 flags) 8971 { 8972 int i, start_cos=0, end_cos=0, local_port; 8973 _bcm_th3_cosq_node_t *node = NULL; 8974 uint32 burst_min, burst_max; 8975 8976 BCM_IF_ERROR_RETURN(_bcm_th3_cosq_localport_resolve(unit, gport, 8977 &local_port)); 8978 if (BCM_GPORT_IS_SET(gport)) { 8979 if ((BCM_GPORT_IS_SCHEDULER(gport)) || 8980 BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport) || 8981 BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 8982 BCM_IF_ERROR_RETURN 8983 (_bcm_th3_cosq_node_get(unit, gport, NULL, 8984 NULL, NULL, &node)); 8985 if (node != NULL) { 8986 start_cos = end_cos = node->hw_index; 8987 } else { 8988 cosq = 0; 8989 } 8990 } else { 8991 if (cosq < 0) { 8992 return BCM_E_PARAM; 8993 } 8994 start_cos = end_cos = cosq; 8995 } 8996 } else { 8997 if (cosq < 0) { 8998 return BCM_E_PARAM; 8999 } 9000 start_cos = end_cos = cosq; 9001 } 9002 9003 burst_min = (kbits_sec_min > 0) ? 9004 _bcm_th3_default_burst_size(unit, local_port, kbits_sec_min) : 0; 9005 9006 burst_max = (kbits_sec_max > 0) ? 9007 _bcm_th3_default_burst_size(unit, local_port, kbits_sec_max) : 0; 9008 9009 for (i = start_cos; i <= end_cos; i++) { 9010 BCM_IF_ERROR_RETURN 9011 (_bcm_th3_cosq_bucket_set(unit, gport, i, kbits_sec_min, 9012 kbits_sec_max, burst_min, burst_max, flags)); 9013 } 9014 9015 return BCM_E_NONE; 9016 } 9017 9018 STATIC int 9019 _bcm_th3_cosq_cpu_port_info_dump(int unit) 9020 { 9021 _bcm_th3_cosq_cpu_port_info_t *port_info; 9022 bcm_port_t port = 0; /* CPU Port */ 9023 _bcm_th3_cosq_node_t *node; 9024 int index; 9025 soc_th3_sched_mode_e sched_mode = 0; 9026 int weight = 0; 9027 char *sched_modes[] = {"X", "SP", "WRR", "WERR"}; 9028 9029 if (!SOC_PORT_VALID(unit, port)) { 9030 return BCM_E_PORT; 9031 } 9032 port_info = _bcm_th3_cosq_cpu_port_info[unit]; 9033 9034 LOG_CLI((BSL_META_U(unit, 9035 "=== CPU PORT ===\n"))); 9036 9037 LOG_CLI((BSL_META_U(unit, 9038 "L0 Nodes\n"))); 9039 for (index = 0; index < _BCM_TH3_NUM_SCHEDULER_PER_PORT; index++) { 9040 /* Node */ 9041 node = &port_info->sched[index]; 9042 9043 BCM_IF_ERROR_RETURN( 9044 soc_th3_cosq_sched_mode_get(unit, port, node->level, index, 9045 &sched_mode, &weight, 0)); 9046 LOG_CLI((BSL_META_U(unit, 9047 " LO.%d: GPORT=0x%x MODE=%s WT=%d\n"), 9048 index, node->gport, 9049 sched_modes[sched_mode], weight)); 9050 } 9051 9052 LOG_CLI((BSL_META_U(unit, 9053 "\nMC Queues\n"))); 9054 for (index = 0; index < _BCM_TH3_NUM_CPU_MCAST_QUEUE; index++) { 9055 int parent_id = 0; 9056 /* MC Queue */ 9057 node = &port_info->mcast[index]; 9058 BCM_IF_ERROR_RETURN( 9059 soc_th3_cosq_sched_mode_get(unit, port, node->level, index, 9060 &sched_mode, &weight, 1)); 9061 BCM_IF_ERROR_RETURN( 9062 _bcm_th3_cosq_node_get(unit, node->parent_gport, NULL, NULL, 9063 &parent_id, NULL)); 9064 LOG_CLI((BSL_META_U(unit, 9065 " MC.%d: GPORT=0x%x MODE=%s WT=%d" 9066 " PARENT=L0.%d\n"), 9067 index, node->gport, 9068 sched_modes[sched_mode], weight, 9069 parent_id)); 9070 } 9071 LOG_CLI((BSL_META_U(unit, 9072 "=========== \n"))); 9073 9074 return BCM_E_NONE; 9075 } 9076 9077 STATIC int 9078 _bcm_th3_cosq_port_info_dump(int unit, bcm_port_t port) 9079 { 9080 _bcm_th3_cosq_port_info_t *port_info; 9081 _bcm_th3_cosq_node_t *node; 9082 soc_th3_cosq_node_t *l1_node; 9083 int index, empty; 9084 soc_th3_sched_mode_e sched_mode = 0; 9085 int weight = 0; 9086 char *sched_modes[] = {"X", "SP", "WRR", "WERR"}; 9087 int l1_parent = -1; 9088 9089 if (!SOC_PORT_VALID(unit, port)) { 9090 return BCM_E_PORT; 9091 } 9092 port_info = &_bcm_th3_cosq_port_info[unit][port]; 9093 9094 empty = TRUE; 9095 for (index = 0; index < _BCM_TH3_NUM_SCHEDULER_PER_PORT; index++) { 9096 if (port_info->sched[index].numq > 0) { 9097 empty = FALSE; 9098 break; 9099 } 9100 } 9101 if (empty) { 9102 for (index = 0; index < _bcm_th3_get_num_ucq(unit); index++) { 9103 if (port_info->ucast[index].numq > 0) { 9104 empty = FALSE; 9105 break; 9106 } 9107 } 9108 } 9109 if (empty) { 9110 for (index = 0; index < _bcm_th3_get_num_mcq(unit); index++) { 9111 if (port_info->mcast[index].numq > 0) { 9112 empty = FALSE; 9113 break; 9114 } 9115 } 9116 } 9117 9118 if (empty == TRUE) { 9119 return BCM_E_NOT_FOUND; 9120 } 9121 9122 LOG_CLI((BSL_META_U(unit, 9123 "=== PORT %d\n"), port)); 9124 9125 for (index = 0; index < _BCM_TH3_NUM_SCHEDULER_PER_PORT; index++) { 9126 /* Node */ 9127 node = &port_info->sched[index]; 9128 if (node->in_use == 0 || node->numq == 0) { 9129 continue; 9130 } 9131 9132 BCM_IF_ERROR_RETURN( 9133 soc_th3_cosq_sched_mode_get(unit, port, node->level, index, 9134 &sched_mode, &weight, 0)); 9135 LOG_CLI((BSL_META_U(unit, 9136 "LO.%d: GPORT=0x%x MODE=%s WT=%d, COS=%d\n"), 9137 index, node->gport, 9138 sched_modes[sched_mode], weight, node->cos)); 9139 } 9140 9141 for (index = 0; index < _bcm_th3_get_num_ucq(unit); index++) { 9142 /* UC Queue */ 9143 int parent_id; 9144 node = &port_info->ucast[index]; 9145 l1_node = 9146 th3_cosq_mmu_info[unit]->th3_port_info[port].mmuq[index].parent; 9147 BCM_IF_ERROR_RETURN(soc_th3_cosq_parent_get(unit, port, index, 9148 node->level, &l1_parent)); 9149 BCM_IF_ERROR_RETURN( 9150 soc_th3_cosq_sched_mode_get(unit, port, l1_node->level, 9151 l1_parent, &sched_mode, &weight, 0)); 9152 BCM_IF_ERROR_RETURN( 9153 _bcm_th3_cosq_node_get(unit, node->parent_gport, NULL, NULL, 9154 &parent_id, NULL)); 9155 LOG_CLI((BSL_META_U(unit, 9156 "UC.%d: GPORT=0x%x MODE=%s WT=%d PARENT=%d\n"), 9157 index, node->gport, 9158 sched_modes[sched_mode], weight, parent_id)); 9159 } 9160 9161 for (index = 0; index < _bcm_th3_get_num_mcq(unit); index++) { 9162 /* MC Queue */ 9163 int parent_id; 9164 node = &port_info->mcast[index]; 9165 l1_node = 9166 th3_cosq_mmu_info[unit]->th3_port_info[port].mmuq[(index + 9167 _bcm_th3_get_num_ucq(unit))].parent; 9168 BCM_IF_ERROR_RETURN(soc_th3_cosq_parent_get(unit, port, 9169 (index + _bcm_th3_get_num_ucq(unit)), 9170 node->level, &l1_parent)); 9171 BCM_IF_ERROR_RETURN( 9172 soc_th3_cosq_sched_mode_get(unit, port, l1_node->level, 9173 l1_parent, &sched_mode, &weight, 1)); 9174 BCM_IF_ERROR_RETURN( 9175 _bcm_th3_cosq_node_get(unit, node->parent_gport, NULL, NULL, 9176 &parent_id, NULL)); 9177 LOG_CLI((BSL_META_U(unit, 9178 "MC.%d: GPORT=0x%x MODE=%s WT=%d PARENT=%d\n"), 9179 index, node->gport, 9180 sched_modes[sched_mode], weight, parent_id)); 9181 } 9182 LOG_CLI((BSL_META_U(unit, 9183 "=========== \n"))); 9184 9185 return BCM_E_NONE; 9186 } 9187 9188 9189 /* 9190 * Function: 9191 * bcm_th3_cosq_sw_dump 9192 * Purpose: 9193 * Displays COS Queue information maintained by software. 9194 * Parameters: 9195 * unit - Device unit number 9196 * Returns: 9197 * None 9198 */ 9199 void 9200 bcm_th3_cosq_sw_dump(int unit) 9201 { 9202 bcm_port_t port; 9203 int ii; 9204 LOG_CLI((BSL_META_U(unit, 9205 "\nSW Information COSQ - Unit %d\n"), unit)); 9206 PBMP_ALL_ITER(unit, port) { 9207 if (IS_CPU_PORT(unit, port)) { 9208 (void)_bcm_th3_cosq_cpu_port_info_dump(unit); 9209 } 9210 (void)_bcm_th3_cosq_port_info_dump(unit, port); 9211 } 9212 for (ii = 0; ii < _BCM_TH3_NUM_TIME_DOMAIN; ii++) { 9213 LOG_CLI((BSL_META_U(unit, 9214 "\nTIME_DOMAIN[%d] - refcnt %d\n"), ii, 9215 th3_time_domain_info[unit][ii].ref_count)); 9216 } 9217 9218 return; 9219 } 9220 9221 9222 /* 9223 * Function: 9224 * _bcm_th3_cosq_port_guarantee_reset 9225 * Purpose: 9226 * Reset the guarantee of priority group, uc queue, mc queue to the default 9227 * Parameters: 9228 * unit - (IN) Unit number. 9229 * port - (IN) Logical port. 9230 * Returns: 9231 * BCM_E_XXX 9232 */ 9233 STATIC int 9234 _bcm_th3_cosq_port_guarantee_reset(int unit, bcm_port_t port) 9235 { 9236 _soc_mmu_device_info_t devcfg; 9237 int lossless, override, default_mtu_cells, idx, numq; 9238 int pg_guarantee, uc_guarantee, mc_guarantee; 9239 int qgroup_uc_guarantee, qgroup_mc_guarantee; 9240 9241 lossless = soc_property_get(unit, spn_MMU_LOSSLESS, 0); 9242 override = soc_property_get(unit, spn_MMU_CONFIG_OVERRIDE, 1); 9243 9244 _soc_th3_mmu_init_dev_config(unit, &devcfg, lossless); 9245 default_mtu_cells = _MMU_CFG_MMU_BYTES_TO_CELLS(devcfg.default_mtu_size + 9246 devcfg.mmu_hdr_byte, 9247 devcfg.mmu_cell_size); 9248 9249 /* priority group */ 9250 for (idx = 0; idx < _TH3_MMU_NUM_PG; idx++) { 9251 pg_guarantee = 0; 9252 if ((idx == 7) && lossless) { 9253 pg_guarantee = default_mtu_cells; 9254 } 9255 if (!override) { 9256 _soc_mmu_cfg_property_get_cells 9257 (unit, port, spn_PRIGROUP, idx, spn_GUARANTEE, FALSE, 9258 &pg_guarantee, devcfg.mmu_cell_size, 9259 _MMU_DEFAULT_THRES_TYPE); 9260 pg_guarantee *= devcfg.mmu_cell_size; 9261 } 9262 BCM_IF_ERROR_RETURN 9263 (_bcm_th3_cosq_ing_res_set(unit, port, idx, 9264 bcmCosqControlIngressPortPGMinLimitBytes, 9265 pg_guarantee)); 9266 } 9267 9268 /* UC */ 9269 numq = _bcm_th3_get_num_ucq(unit); 9270 for (idx = 0; idx < numq; idx++) { 9271 uc_guarantee = 0; 9272 if (!override) { 9273 _soc_mmu_cfg_property_get_cells 9274 (unit, port, spn_QUEUE, idx, spn_GUARANTEE, FALSE, 9275 &uc_guarantee, devcfg.mmu_cell_size, 9276 _MMU_DEFAULT_THRES_TYPE); 9277 uc_guarantee *= devcfg.mmu_cell_size; 9278 } 9279 BCM_IF_ERROR_RETURN 9280 (_bcm_th3_cosq_egr_queue_set(unit, port, idx, 9281 bcmCosqControlEgressUCQueueMinLimitBytes, 9282 uc_guarantee)); 9283 } 9284 9285 /* MC */ 9286 numq = _bcm_th3_get_num_ucq(unit) + _bcm_th3_get_num_mcq(unit); 9287 for (idx = _bcm_th3_get_num_ucq(unit); idx < numq; idx++) { 9288 mc_guarantee = 0; 9289 if (!override) { 9290 _soc_mmu_cfg_property_get_cells 9291 (unit, port, spn_MQUEUE, idx, spn_GUARANTEE, FALSE, 9292 &mc_guarantee, devcfg.mmu_cell_size, 9293 _MMU_DEFAULT_THRES_TYPE); 9294 mc_guarantee *= devcfg.mmu_cell_size; 9295 } 9296 BCM_IF_ERROR_RETURN 9297 (_bcm_th3_cosq_egr_queue_set(unit, port, idx, 9298 bcmCosqControlEgressMCQueueMinLimitBytes, 9299 mc_guarantee)); 9300 } 9301 9302 /* QGROUP UC */ 9303 numq = _bcm_th3_get_num_ucq(unit); 9304 for (idx = 0; idx < numq; idx++) { 9305 qgroup_uc_guarantee = 0; 9306 if (!override) { 9307 _soc_mmu_cfg_property_get_cells 9308 (unit, -1, spn_QGROUP, idx, spn_GUARANTEE, FALSE, 9309 &qgroup_uc_guarantee, devcfg.mmu_cell_size, 9310 _MMU_DEFAULT_THRES_TYPE); 9311 qgroup_uc_guarantee *= devcfg.mmu_cell_size; 9312 } 9313 BCM_IF_ERROR_RETURN 9314 (_bcm_th3_cosq_qgroup_limit_set(unit, port, idx, 9315 bcmCosqControlEgressUCQueueGroupMinLimitBytes, 9316 qgroup_uc_guarantee)); 9317 } 9318 9319 /* QGROUP MC */ 9320 numq = _bcm_th3_get_num_ucq(unit) + _bcm_th3_get_num_mcq(unit); 9321 for (idx = _bcm_th3_get_num_ucq(unit); idx < numq; idx++) { 9322 qgroup_mc_guarantee = 0; 9323 if (!override) { 9324 _soc_mmu_cfg_property_get_cells 9325 (unit, -1, spn_QGROUP, idx, spn_GUARANTEE_MC, FALSE, 9326 &qgroup_mc_guarantee, devcfg.mmu_cell_size, 9327 _MMU_DEFAULT_THRES_TYPE); 9328 qgroup_mc_guarantee *= devcfg.mmu_cell_size; 9329 } 9330 BCM_IF_ERROR_RETURN 9331 (_bcm_th3_cosq_qgroup_limit_set(unit, port, idx, 9332 bcmCosqControlEgressMCQueueGroupMinLimitBytes, 9333 qgroup_mc_guarantee)); 9334 } 9335 9336 return BCM_E_NONE; 9337 } 9338 9339 /* 9340 * Function: 9341 * bcm_th3_cosq_port_detach 9342 * Purpose: 9343 * Clear cosq configuration of port 9344 * Parameters: 9345 * unit - (IN) Unit number. 9346 * port - (IN) Logical port. 9347 * Returns: 9348 * SOC_E_XXX 9349 */ 9350 int 9351 bcm_th3_cosq_port_detach(int unit, bcm_port_t port) 9352 { 9353 soc_info_t *si = &SOC_INFO(unit); 9354 _bcm_th3_cosq_port_info_t *port_info = NULL; 9355 uint32 profile_index; 9356 uint32 entry[SOC_MAX_MEM_WORDS]; 9357 9358 if (IS_CPU_PORT(unit, port) || IS_LB_PORT(unit, port) || 9359 IS_MANAGEMENT_PORT(unit, port)) { 9360 return BCM_E_PARAM; 9361 } 9362 LOG_INFO(BSL_LS_BCM_COSQ, 9363 (BSL_META_U(unit, 9364 "bcm_th3_cosq_port_detach port %d\n"), 9365 port)); 9366 9367 /* When update guarantee of PG/UC/MC via API, the shared limit is adjusted 9368 * accordingly. So MUST reset the gurarntee to the default value before 9369 * deleting the port to recover the shared limit. */ 9370 BCM_IF_ERROR_RETURN 9371 (_bcm_th3_cosq_port_guarantee_reset(unit, port)); 9372 9373 /* Destroy cosq gport tree on port */ 9374 port_info = &_bcm_th3_cosq_port_info[unit][port]; 9375 sal_memset(port_info, 0, sizeof(_bcm_th3_cosq_port_info_t)); 9376 9377 /* Reset soc gport tree on port */ 9378 BCM_IF_ERROR_RETURN(soc_tomahawk3_cosq_port_info_init(unit, port)); 9379 9380 /* Decrease the reference of COS_MAP_PROFILE */ 9381 SOC_IF_ERROR_RETURN 9382 (soc_mem_read(unit, COS_MAP_SELm, MEM_BLOCK_ALL, port, &entry)); 9383 profile_index = soc_mem_field32_get(unit, COS_MAP_SELm, &entry, SELECTf); 9384 SOC_IF_ERROR_RETURN 9385 (soc_profile_mem_delete(unit, _bcm_th3_cos_map_profile[unit], 9386 profile_index * 16)); 9387 9388 /* Clear cosq */ 9389 si->port_num_cosq[port] = 0; 9390 si->port_cosq_base[port] = 0; 9391 si->port_num_uc_cosq[port] = 0; 9392 si->port_uc_cosq_base[port] = 0; 9393 si->port_num_ext_cosq[port] = 0; 9394 9395 return BCM_E_NONE; 9396 } 9397 9398 9399 /* 9400 * Function: 9401 * bcm_th3_cosq_port_attach 9402 * Purpose: 9403 * Initialize Cosq for newly added port 9404 * Parameters: 9405 * unit - (IN) Unit number. 9406 * port - (IN) Logical port. 9407 * Returns: 9408 * SOC_E_XXX 9409 */ 9410 int 9411 bcm_th3_cosq_port_attach(int unit, bcm_port_t port) 9412 { 9413 soc_info_t *si = &SOC_INFO(unit); 9414 _bcm_th3_cosq_port_info_t *port_info = NULL; 9415 int default_mode = BCM_COSQ_WEIGHTED_ROUND_ROBIN, default_weight = 1; 9416 int i, itm_map, shd_size, pipe; 9417 int L0[_BCM_TH3_COS_MAX]; 9418 int schedq[_BCM_TH3_COS_MAX]; 9419 int mmuq[_BCM_TH3_COS_MAX]; 9420 int cos_list[_BCM_TH3_COS_MAX]; 9421 soc_reg_t reg; 9422 uint64 rval_64; 9423 soc_field_t mmuq_field[12] = { 9424 MMU_Q_NUM_0f, MMU_Q_NUM_1f, 9425 MMU_Q_NUM_2f, MMU_Q_NUM_3f, 9426 MMU_Q_NUM_4f, MMU_Q_NUM_5f, 9427 MMU_Q_NUM_6f, MMU_Q_NUM_7f, 9428 MMU_Q_NUM_8f, MMU_Q_NUM_9f, 9429 MMU_Q_NUM_10f, MMU_Q_NUM_11f, 9430 }; 9431 9432 if (IS_CPU_PORT(unit, port) || IS_LB_PORT(unit, port) || 9433 IS_MANAGEMENT_PORT(unit, port)) { 9434 return BCM_E_PARAM; 9435 } 9436 LOG_INFO(BSL_LS_BCM_COSQ, 9437 (BSL_META_U(unit, 9438 "bcm_th3_cosq_port_attach port %d\n"), 9439 port)); 9440 9441 /* Increase the reference of default COS_MAP_PROFILE */ 9442 BCM_IF_ERROR_RETURN 9443 (soc_mem_field32_modify(unit, COS_MAP_SELm, port, SELECTf, 0)); 9444 BCM_IF_ERROR_RETURN 9445 (soc_profile_mem_reference(unit, _bcm_th3_cos_map_profile[unit], 0, 0)); 9446 9447 /* set scheduler profile to port 0 */ 9448 reg = MMU_PPSCH_SCHQ_MMUQ_PROFILEr; 9449 SOC_IF_ERROR_RETURN(soc_reg64_get(unit, reg, port, 0, &rval_64)); 9450 9451 for (i = 0; i < _BCM_TH3_NUM_SCHEDULER_PER_PORT; i++) { 9452 L0[i] = L1_TO_L0_MAPPING[unit][0][i]; 9453 schedq[i] = i; 9454 mmuq[i] = soc_reg64_field32_get(unit, reg, rval_64, mmuq_field[i]); 9455 cos_list[i] = L0_TO_COSQ_MAPPING[unit][0][i]; 9456 } 9457 soc_tomahawk3_sched_update_flex_per_port(unit, port, 0, L0, schedq, mmuq, cos_list); 9458 9459 /* Create gport tree */ 9460 _BCM_TH3_MMU_INFO(unit)->gport_tree_created = FALSE; 9461 BCM_IF_ERROR_RETURN(_bcm_th3_cosq_gport_tree_create(unit, port)); 9462 _BCM_TH3_MMU_INFO(unit)->gport_tree_created = TRUE; 9463 9464 /* Set Default Scheduler Configuration on the ports */ 9465 port_info = &_bcm_th3_cosq_port_info[unit][port]; 9466 for (i = 0; i < _BCM_TH3_NUM_SCHEDULER_PER_PORT; i++) { 9467 if (port_info->sched[i].in_use == 0 || port_info->sched[i].numq == 0) { 9468 continue; 9469 } 9470 9471 BCM_IF_ERROR_RETURN( 9472 bcm_th3_cosq_gport_sched_set(unit, port_info->sched[i].gport, 9473 -1, default_mode, default_weight)); 9474 } 9475 for (i = 0; i < _bcm_th3_get_num_ucq(unit); i++) { 9476 BCM_IF_ERROR_RETURN 9477 (bcm_th3_cosq_gport_sched_set(unit, port_info->ucast[i].gport, 9478 -1, default_mode, default_weight)); 9479 } 9480 for (i = 0; i < _bcm_th3_get_num_mcq(unit); i++) { 9481 BCM_IF_ERROR_RETURN 9482 (bcm_th3_cosq_gport_sched_set(unit, port_info->mcast[i].gport, 9483 -1, default_mode, default_weight)); 9484 } 9485 9486 /* Set MMU threshold and scheduler profiles to profile 0 9487 * Customer can change the profile after flexport sequence is done */ 9488 BCM_IF_ERROR_RETURN(bcm_tomahawk3_cosq_port_profile_set(unit, port, 9489 bcmCosqProfilePGProperties, 0)); 9490 BCM_IF_ERROR_RETURN(bcm_tomahawk3_cosq_port_profile_set(unit, port, 9491 bcmCosqProfileIntPriToPGMap, 0)); 9492 BCM_IF_ERROR_RETURN(bcm_tomahawk3_cosq_port_profile_set(unit, port, 9493 bcmCosqProfilePFCAndQueueHierarchy, 0)); 9494 9495 /* Update shared limit of new ports in case the shared limit has been 9496 * adjusted by bcm_cosq_control_set() API */ 9497 SOC_IF_ERROR_RETURN(soc_port_pipe_get(unit, port, &pipe)); 9498 shd_size = 0; 9499 for (i = 0; i < NUM_ITM(unit); i++) { 9500 itm_map = si->itm_ipipe_map[i]; 9501 if (itm_map & (1 << pipe)) { 9502 shd_size = _BCM_TH3_MMU_INFO(unit)->shared_limit[i]; 9503 } 9504 } 9505 9506 BCM_IF_ERROR_RETURN( 9507 soc_th3_mmu_config_flex_thresholds(unit, port, shd_size)); 9508 9509 return BCM_E_NONE; 9510 } 9511 9512 int 9513 bcm_th3_cosq_gport_mapping_set(int unit, bcm_port_t ing_port, 9514 bcm_cos_t int_pri, uint32 flags, 9515 bcm_gport_t gport, bcm_cos_queue_t cosq) 9516 { 9517 bcm_port_t local_port; 9518 9519 if ((int_pri < 0) || (int_pri >= _TH3_MMU_NUM_INT_PRI)) { 9520 return BCM_E_PARAM; 9521 } 9522 9523 BCM_IF_ERROR_RETURN(_bcm_th3_cosq_localport_resolve(unit, ing_port, 9524 &local_port)); 9525 9526 if ((cosq < 0) || (cosq >= _TH3_PORT_NUM_COS(unit, local_port))) { 9527 return BCM_E_PARAM; 9528 } 9529 9530 return _bcm_th3_cosq_mapping_set(unit, ing_port, int_pri, flags, gport, 9531 cosq, cosq); 9532 } 9533 9534 int 9535 bcm_th3_cosq_gport_mapping_get(int unit, bcm_port_t ing_port, 9536 bcm_cos_t int_pri, uint32 flags, 9537 bcm_gport_t *gport, bcm_cos_queue_t *cosq) 9538 { 9539 if (gport == NULL || cosq == NULL) { 9540 return BCM_E_PARAM; 9541 } 9542 9543 if ((int_pri < 0) || (int_pri >= _TH3_MMU_NUM_INT_PRI)) { 9544 return BCM_E_PARAM; 9545 } 9546 9547 return _bcm_th3_cosq_mapping_get(unit, ing_port, int_pri, flags, gport, 9548 cosq); 9549 } 9550 9551 /*Function to return the number of child nodes and child node gport array for 9552 * scheduler gport */ 9553 int 9554 _bcm_th3_cosq_sched_node_child_get(int unit, bcm_gport_t sched_gport, int 9555 *num_uc_child, int *uc_queue, int *num_mc_child, int *mc_queue) 9556 { 9557 _bcm_th3_cosq_port_info_t *port_info = NULL; 9558 _bcm_th3_cosq_cpu_port_info_t *cpu_port_info = NULL; 9559 9560 int local_port, id; 9561 _bcm_th3_cosq_index_style_t style = _BCM_TH3_COSQ_INDEX_STYLE_COS; 9562 int num_mc, num_uc; 9563 int cpu_mc_base; 9564 soc_info_t *si = &SOC_INFO(unit); 9565 9566 if (!BCM_GPORT_IS_SCHEDULER(sched_gport)) { 9567 /* Function valid only scheduler gport*/ 9568 return BCM_E_INTERNAL; 9569 } 9570 if ((num_uc_child == NULL) || (uc_queue == NULL) || (num_mc_child == NULL) 9571 || (mc_queue == NULL)) { 9572 return BCM_E_INTERNAL; 9573 } 9574 9575 BCM_IF_ERROR_RETURN 9576 (_bcm_th3_cosq_index_resolve 9577 (unit, sched_gport, -1, style, &local_port, NULL, NULL)); 9578 9579 if (!IS_CPU_PORT(unit, local_port)) { 9580 port_info = &_bcm_th3_cosq_port_info[unit][local_port]; 9581 num_uc = 0; 9582 num_mc = 0; 9583 for (id = 0; id < si->port_num_uc_cosq[local_port]; id++) { 9584 if (port_info->ucast[id].numq == 0) { 9585 continue; 9586 } 9587 if (port_info->ucast[id].parent_gport == sched_gport) { 9588 uc_queue[num_uc] = port_info->ucast[id].hw_index % 9589 si->port_num_uc_cosq[local_port]; 9590 num_uc++; 9591 } 9592 } 9593 for (id = 0; id < si->port_num_cosq[local_port]; id++) { 9594 if (port_info->mcast[id].numq == 0) { 9595 continue; 9596 } 9597 if (port_info->mcast[id].parent_gport == sched_gport) { 9598 mc_queue[num_mc] = port_info->mcast[id].hw_index % 9599 si->port_num_cosq[local_port]; 9600 num_mc++; 9601 } 9602 } 9603 } else { 9604 /* CPU port */ 9605 num_uc = -1; 9606 num_mc = 0; 9607 cpu_port_info = _bcm_th3_cosq_cpu_port_info[unit]; 9608 for (id = 0; id < _BCM_TH3_NUM_CPU_MCAST_QUEUE; id++) { 9609 if (cpu_port_info->mcast[id].numq == 0) { 9610 continue; 9611 } 9612 if (cpu_port_info->mcast[id].parent_gport == sched_gport) { 9613 cpu_mc_base = si->port_cosq_base[CMIC_PORT(unit)]; 9614 mc_queue[num_mc] = (cpu_port_info->mcast[id].hw_index - 9615 cpu_mc_base) % NUM_CPU_COSQ(unit); 9616 num_mc++; 9617 } 9618 } 9619 } 9620 *num_mc_child = num_mc; 9621 *num_uc_child = num_uc; 9622 9623 return BCM_E_NONE; 9624 } 9625 9626 9627 /* 9628 * Function: 9629 * bcm_th3_cosq_field_classifier_get 9630 * Purpose: 9631 * Get classifier type information. 9632 * Parameters: 9633 * unit - (IN) Unit number. 9634 * classifier_id - (IN) Classifier ID 9635 * classifier - (OUT) Classifier info 9636 * Returns: 9637 * BCM_E_xxx 9638 */ 9639 int 9640 bcm_th3_cosq_field_classifier_get( 9641 int unit, 9642 int classifier_id, 9643 bcm_cosq_classifier_t *classifier) 9644 { 9645 if (classifier == NULL) { 9646 return BCM_E_PARAM; 9647 } 9648 sal_memset(classifier, 0, sizeof(bcm_cosq_classifier_t)); 9649 9650 if (_BCM_COSQ_CLASSIFIER_IS_FIELD(classifier_id)) { 9651 classifier->flags |= BCM_COSQ_CLASSIFIER_FIELD; 9652 } 9653 9654 return BCM_E_NONE; 9655 } 9656 9657 /* 9658 * Function: 9659 * bcm_th3_cosq_field_classifier_id_create 9660 * Purpose: 9661 * Create a cosq classifier. 9662 * Parameters: 9663 * unit - (IN) Unit number. 9664 * classifier - (IN) Classifier attributes 9665 * classifier_id - (OUT) Classifier ID 9666 * Returns: 9667 * BCM_E_xxx 9668 */ 9669 int 9670 bcm_th3_cosq_field_classifier_id_create( 9671 int unit, 9672 bcm_cosq_classifier_t *classifier, 9673 int *classifier_id) 9674 { 9675 int rv; 9676 int ref_count = 0; 9677 int ent_per_set = _TH3_MMU_NUM_INT_PRI; 9678 int i; 9679 9680 if (NULL == classifier || NULL == classifier_id) { 9681 return BCM_E_PARAM; 9682 } 9683 9684 for (i = 0; i < (SOC_MEM_SIZE(unit, IFP_COS_MAPm) - ent_per_set) ; i += ent_per_set) { 9685 rv = soc_profile_mem_ref_count_get( 9686 unit, _bcm_th3_ifp_cos_map_profile[unit], i, &ref_count); 9687 if (SOC_FAILURE(rv)) { 9688 return rv; 9689 } 9690 if (0 == ref_count) { 9691 break; 9692 } 9693 } 9694 9695 if (i >= (SOC_MEM_SIZE(unit, IFP_COS_MAPm) - ent_per_set) && ref_count != 0) { 9696 *classifier_id = 0; 9697 return BCM_E_RESOURCE; 9698 } 9699 9700 _BCM_COSQ_CLASSIFIER_FIELD_SET(*classifier_id, (i / ent_per_set)); 9701 9702 return BCM_E_NONE; 9703 } 9704 9705 /* 9706 * Function: 9707 * bcm_th3_cosq_field_classifier_map_set 9708 * Purpose: 9709 * Set internal priority to ingress field processor CoS queue 9710 * override mapping. 9711 * Parameters: 9712 * unit - (IN) Unit number. 9713 * classifier_id - (IN) Classifier ID 9714 * count - (IN) Number of elements in priority_array and 9715 * cosq_array. 9716 * priority_array - (IN) Array of internal priorities 9717 * cosq_array - (IN) Array of COS queues 9718 * Returns: 9719 * BCM_E_xxx 9720 * Notes: 9721 * Supported count value is [0-16] and 48 9722 * When count = [0-16] 9723 * Array Index [15-0] : Maps Prio[15-0] to UC, MC 9724 * and RQE cos[15-0] 9725 * When count = 48 9726 * Prio Array Index Map 9727 * Array Index [15-0] : Maps Prio[15-0] to UC cos[15-0] 9728 * Array Index [31-16] : Maps Prio[15-0] to MC cos[15-0] 9729 * Array Index [47-32] : Maps Prio[15-0] to RQE cos[15-0] 9730 */ 9731 int 9732 bcm_th3_cosq_field_classifier_map_set( 9733 int unit, 9734 int classifier_id, 9735 int count, 9736 bcm_cos_t *priority_array, 9737 bcm_cos_queue_t *cosq_array) 9738 { 9739 int rv; 9740 int i; 9741 int max_entries = _TH3_MMU_NUM_INT_PRI; 9742 uint32 index, new_index; 9743 void *entries[1]; 9744 ifp_cos_map_entry_t ent_buf[_TH3_MMU_NUM_INT_PRI]; 9745 soc_field_t field = -1; 9746 int min_max_qnum; 9747 uint16 dev_id; 9748 uint8 rev_id; 9749 9750 soc_cm_get_id(unit, &dev_id, &rev_id); 9751 9752 /* Input parameter check. */ 9753 if (!_BCM_COSQ_CLASSIFIER_IS_FIELD(classifier_id)) { 9754 return BCM_E_PARAM; 9755 } 9756 9757 if (NULL == priority_array || NULL == cosq_array) { 9758 return BCM_E_PARAM; 9759 } 9760 9761 if ((count > max_entries) && (count != (max_entries * 3))) { 9762 return BCM_E_PARAM; 9763 } 9764 9765 sal_memset(ent_buf, 0, sizeof(ifp_cos_map_entry_t) * max_entries); 9766 entries[0] = ent_buf; 9767 9768 if (rev_id == BCM56980_A0_REV_ID) { 9769 min_max_qnum = MIN(MIN(_bcm_th3_get_num_mcq(unit), _bcm_th3_get_num_ucq(unit)), 9770 _TH3_A0_MMU_NUM_RQE_QUEUES); 9771 } else { 9772 min_max_qnum = MIN(MIN(_bcm_th3_get_num_mcq(unit), _bcm_th3_get_num_ucq(unit)), 9773 _TH3_MMU_NUM_RQE_QUEUES); 9774 } 9775 9776 if (count != (max_entries * 3)) { 9777 for (i = 0; i < count; i++) { 9778 if (priority_array[i] < max_entries) { 9779 /* When count != max_entries * 3 9780 We program the same mapping for all three 9781 fields UC/MC/RQE queues. 9782 Hence cos_array[i] cannot have value more than 9783 equal to MIN(MAX UC_COS, MAX MC_COS, MAX RQE_NUM) */ 9784 if ((cosq_array[i] < 0) || 9785 (cosq_array[i] >= min_max_qnum)) { 9786 return BCM_E_PARAM; 9787 } 9788 soc_mem_field32_set(unit, IFP_COS_MAPm, &ent_buf[priority_array[i]], 9789 IFP_MC_COSf, cosq_array[i]); 9790 soc_mem_field32_set(unit, IFP_COS_MAPm, &ent_buf[priority_array[i]], 9791 IFP_UC_COSf, cosq_array[i]); 9792 soc_mem_field32_set(unit, IFP_COS_MAPm, &ent_buf[priority_array[i]], 9793 IFP_RQE_Q_NUMf, cosq_array[i]); 9794 } 9795 } 9796 } else { 9797 for (i = 0; i < count; i++) { 9798 if (priority_array[i] < max_entries) { 9799 if (i < max_entries) { 9800 /* Number of UCAST queue per port can be 6,8,10,12 based on 9801 MCQ mode */ 9802 if ((cosq_array[i] < 0) || 9803 (cosq_array[i] >= _bcm_th3_get_num_ucq(unit))) { 9804 return BCM_E_PARAM; 9805 } 9806 field = IFP_UC_COSf; 9807 } else if (i < (max_entries * 2)) { 9808 /* Number of MCAST queue per port can be 0,2,4,6 based on 9809 MCQ MODE */ 9810 if ((cosq_array[i] < 0) || 9811 (cosq_array[i] >= _bcm_th3_get_num_mcq(unit))) { 9812 return BCM_E_PARAM; 9813 } 9814 field = IFP_MC_COSf; 9815 } else { 9816 /* Number of RQE queue per unit = 3 */ 9817 if (rev_id == BCM56980_A0_REV_ID) { 9818 if ((cosq_array[i] < 0) || 9819 (cosq_array[i] >= _TH3_A0_MMU_NUM_RQE_QUEUES)) { 9820 return BCM_E_PARAM; 9821 } 9822 } else { 9823 if ((cosq_array[i] < 0) || 9824 (cosq_array[i] >= _TH3_MMU_NUM_RQE_QUEUES)) { 9825 return BCM_E_PARAM; 9826 } 9827 } 9828 field = IFP_RQE_Q_NUMf; 9829 } 9830 soc_mem_field32_set(unit, IFP_COS_MAPm, &ent_buf[priority_array[i]], 9831 field, cosq_array[i]); 9832 } 9833 } 9834 } 9835 9836 index = _BCM_COSQ_CLASSIFIER_FIELD_GET(classifier_id); 9837 9838 rv = soc_profile_mem_delete(unit, _bcm_th3_ifp_cos_map_profile[unit], 9839 index * max_entries); 9840 9841 /* If rv = SOC_E_NONE means that there exists a 9842 * mapping for given classifier_id which is now 9843 * successfully deleted and we can overwrite. 9844 * rv = SOC_E_NOT_FOUND means there was no mapping 9845 * for given classifier_id and we can create a new mapping 9846 * Otherwise there is something else wrong and we return 9847 * the error value returned by soc_profile_mem_delete() 9848 */ 9849 if ((rv != SOC_E_NONE) && (rv != SOC_E_NOT_FOUND)) { 9850 return rv; 9851 } 9852 9853 SOC_IF_ERROR_RETURN 9854 (soc_profile_mem_add(unit, _bcm_th3_ifp_cos_map_profile[unit], 9855 entries, max_entries, &new_index)); 9856 9857 /* If we get (index == new_index / max_entries) means we have 9858 * a successful mapping operation. 9859 * But if they are not equal which means there already exists 9860 * a similar mapping associated with other classifier_id hence 9861 * we return BCM_E_EXISTS. 9862 */ 9863 9864 if (index != (new_index / max_entries)) { 9865 SOC_IF_ERROR_RETURN 9866 (soc_profile_mem_delete(unit, _bcm_th3_ifp_cos_map_profile[unit], 9867 new_index)); 9868 return BCM_E_EXISTS; 9869 } 9870 9871 return BCM_E_NONE; 9872 } 9873 9874 /* 9875 * Function: 9876 * bcm_th3_cosq_field_classifier_map_get 9877 * Purpose: 9878 * Get internal priority to ingress field processor CoS queue 9879 * override mapping information. 9880 * Parameters: 9881 * unit - (IN) Unit number. 9882 * classifier_id - (IN) Classifier ID 9883 * array_max - (IN) Size of priority_array and cosq_array 9884 * priority_array - (IN) Array of internal priorities 9885 * cosq_array - (OUT) Array of COS queues 9886 * array_count - (OUT) Size of cosq_array 9887 * Returns: 9888 * BCM_E_xxx 9889 * Notes: 9890 * Supported array_max = [0-16] and 48 9891 * When array_max = [0-16] 9892 * Array Index [15-0] : Maps Prio[15-0] to UC cos[15-0] 9893 * When array_max = 48 9894 * Prio Array Index Map 9895 * Array Index [15-0] : Maps Prio[15-0] to UC cos[15-0] 9896 * Array Index [31-16] : Maps Prio[15-0] to MC cos[15-0] 9897 * Array Index [47-32] : Maps Prio[15-0] to RQE cos[15-0] 9898 */ 9899 int 9900 bcm_th3_cosq_field_classifier_map_get( 9901 int unit, 9902 int classifier_id, 9903 int array_max, 9904 bcm_cos_t *priority_array, 9905 bcm_cos_queue_t *cosq_array, 9906 int *array_count) 9907 { 9908 int rv; 9909 int i; 9910 int ent_per_set = _TH3_MMU_NUM_INT_PRI; 9911 uint32 index; 9912 void *entries[1]; 9913 ifp_cos_map_entry_t ent_buf[_TH3_MMU_NUM_INT_PRI]; 9914 soc_field_t field = -1; 9915 9916 /* Input parameter check. */ 9917 if (NULL == priority_array || NULL == cosq_array || NULL == array_count) { 9918 return BCM_E_PARAM; 9919 } 9920 9921 sal_memset(ent_buf, 0, sizeof(ifp_cos_map_entry_t) * ent_per_set); 9922 entries[0] = ent_buf; 9923 9924 /* Get profile table entry set base index. */ 9925 index = _BCM_COSQ_CLASSIFIER_FIELD_GET(classifier_id); 9926 9927 /* Read out entries from profile table into allocated buffer. */ 9928 rv = soc_profile_mem_get(unit, _bcm_th3_ifp_cos_map_profile[unit], 9929 index * ent_per_set, ent_per_set, entries); 9930 if (SOC_FAILURE(rv)) { 9931 return rv; 9932 } 9933 9934 if (array_max <= ent_per_set) { 9935 *array_count = array_max; 9936 } else if ((array_max > ent_per_set) && (array_max < (ent_per_set * 3))) { 9937 return BCM_E_PARAM; 9938 } else { 9939 *array_count = ent_per_set * 3; 9940 } 9941 /* Copy values into API OUT parameters. */ 9942 for (i = 0; i < *array_count; i++) { 9943 if (priority_array[i % 16] >= _TH3_MMU_NUM_INT_PRI) { 9944 return BCM_E_PARAM; 9945 } 9946 if (i < ent_per_set) { 9947 field = IFP_UC_COSf; 9948 } else if (i < (ent_per_set * 2)) { 9949 field = IFP_MC_COSf; 9950 } else { 9951 field = IFP_RQE_Q_NUMf; 9952 } 9953 cosq_array[i] = soc_mem_field32_get(unit, IFP_COS_MAPm, 9954 &ent_buf[priority_array[i]], 9955 field); 9956 } 9957 9958 return BCM_E_NONE; 9959 } 9960 9961 /* 9962 * Function: 9963 * bcm_th3_cosq_field_classifier_map_clear 9964 * Purpose: 9965 * Delete an internal priority to ingress field processor CoS queue 9966 * override mapping profile set. 9967 * Parameters: 9968 * unit - (IN) Unit number. 9969 * classifier_id - (IN) Classifier ID 9970 * Returns: 9971 * BCM_E_xxx 9972 */ 9973 int 9974 bcm_th3_cosq_field_classifier_map_clear(int unit, int classifier_id) 9975 { 9976 int ent_per_set = _TH3_MMU_NUM_INT_PRI; 9977 uint32 index; 9978 9979 /* Get profile table entry set base index. */ 9980 index = _BCM_COSQ_CLASSIFIER_FIELD_GET(classifier_id); 9981 9982 /* Delete the profile entries set. */ 9983 SOC_IF_ERROR_RETURN 9984 (soc_profile_mem_delete(unit, 9985 _bcm_th3_ifp_cos_map_profile[unit], 9986 index * ent_per_set)); 9987 return BCM_E_NONE; 9988 } 9989 9990 /* 9991 * Function: 9992 * bcm_th3_cosq_field_classifier_id_destroy 9993 * Purpose: 9994 * Free resource associated with this field classifier id. 9995 * Parameters: 9996 * unit - (IN) Unit number. 9997 * classifier_id - (IN) Classifier ID 9998 * Returns: 9999 * BCM_E_xxx 10000 */ 10001 int 10002 bcm_th3_cosq_field_classifier_id_destroy(int unit, int classifier_id) 10003 { 10004 return BCM_E_NONE; 10005 } 10006 10007 /* 10008 * Function: 10009 * _bcm_th3_cosq_field_reserved_classifier_get 10010 * Purpose: 10011 * Get reserved field classifier id. 10012 * Parameters: 10013 * unit - (IN) Unit number. 10014 * classifier_id - (OUT) Classifier ID. 10015 * port - (OUT) Port reserved. 10016 * Returns: 10017 * BCM_E_xxx 10018 */ 10019 int 10020 _bcm_th3_cosq_field_reserved_classifier_get(int unit, int *classifier_id, 10021 bcm_port_t *port) 10022 { 10023 _BCM_COSQ_CLASSIFIER_FIELD_SET(*classifier_id, _TH3_IFP_COS_MAP_RSVD_PROF); 10024 *port = _TH3_MMU_SPARE_DST_PORT; 10025 return BCM_E_NONE; 10026 } 10027 10028 /* 10029 * Function: 10030 * bcm_th3_cosq_cpu_cosq_enable_set 10031 * Purpose: 10032 * To enable/disable Rx of packets on the specified CPU cosq. 10033 * Parameters: 10034 * unit - (IN) Unit number. 10035 * cosq - (IN) CPU Cosq ID 10036 * enable - (IN) Enable/Disable 10037 * Returns: 10038 * BCM_E_xxx 10039 */ 10040 int 10041 bcm_th3_cosq_cpu_cosq_enable_set(int unit, bcm_cos_queue_t cosq, int enable) 10042 { 10043 uint32 entry[SOC_MAX_MEM_WORDS]; 10044 int index, enable_status; 10045 _bcm_th3_cosq_cpu_cosq_config_t *cpu_cosq_config; 10046 soc_info_t *si; 10047 10048 si = &SOC_INFO(unit); 10049 10050 if ((cosq < 0) || (cosq >= NUM_CPU_COSQ(unit))) { 10051 return BCM_E_PARAM; 10052 } 10053 10054 cpu_cosq_config = _bcm_th3_cosq_cpu_cosq_config[unit][cosq]; 10055 10056 if (!cpu_cosq_config) { 10057 return BCM_E_INTERNAL; 10058 } 10059 if (enable) { 10060 enable = 1; 10061 } 10062 10063 BCM_IF_ERROR_RETURN(bcm_th3_cosq_cpu_cosq_enable_get(unit, cosq, 10064 &enable_status)); 10065 if (enable == enable_status) { 10066 return BCM_E_NONE; 10067 } 10068 10069 index = si->port_cosq_base[CMIC_PORT(unit)] + cosq; 10070 10071 /* To set DB and QE entries */ 10072 BCM_IF_ERROR_RETURN 10073 (soc_mem_read(unit, MMU_THDO_QUEUE_CONFIGm, MEM_BLOCK_ALL, index, &entry)); 10074 10075 /* When enabled, restore the Min and Shared from the cached value */ 10076 if (!enable) { 10077 cpu_cosq_config->q_min_limit = soc_mem_field32_get(unit, 10078 MMU_THDO_QUEUE_CONFIGm, 10079 &entry, 10080 MIN_LIMITf); 10081 cpu_cosq_config->q_shared_limit = soc_mem_field32_get(unit, 10082 MMU_THDO_QUEUE_CONFIGm, 10083 &entry, 10084 SHARED_LIMITf); 10085 cpu_cosq_config->q_limit_dynamic = soc_mem_field32_get(unit, 10086 MMU_THDO_QUEUE_CONFIGm, 10087 &entry, 10088 LIMIT_DYNAMICf); 10089 cpu_cosq_config->q_limit_enable = soc_mem_field32_get(unit, 10090 MMU_THDO_QUEUE_CONFIGm, 10091 &entry, 10092 LIMIT_ENABLEf); 10093 cpu_cosq_config->q_color_limit_enable = soc_mem_field32_get(unit, 10094 MMU_THDO_QUEUE_CONFIGm, 10095 &entry, 10096 COLOR_ENABLEf); 10097 } 10098 soc_mem_field32_set(unit, MMU_THDO_QUEUE_CONFIGm, &entry, LIMIT_DYNAMICf, 10099 enable ? cpu_cosq_config->q_limit_dynamic : 0); 10100 soc_mem_field32_set(unit, MMU_THDO_QUEUE_CONFIGm, &entry, LIMIT_ENABLEf, 10101 enable ? cpu_cosq_config->q_limit_enable : 1); 10102 soc_mem_field32_set(unit, MMU_THDO_QUEUE_CONFIGm, &entry, COLOR_ENABLEf, 10103 enable ? cpu_cosq_config->q_color_limit_enable : 1); 10104 soc_mem_field32_set(unit, MMU_THDO_QUEUE_CONFIGm, &entry, MIN_LIMITf, 10105 enable ? cpu_cosq_config->q_min_limit : 0); 10106 soc_mem_field32_set(unit, MMU_THDO_QUEUE_CONFIGm, &entry, SHARED_LIMITf, 10107 enable ? cpu_cosq_config->q_shared_limit : 0); 10108 cpu_cosq_config->enable = enable; 10109 BCM_IF_ERROR_RETURN( 10110 soc_mem_write(unit, MMU_THDO_QUEUE_CONFIGm, MEM_BLOCK_ALL, index, &entry)); 10111 10112 return BCM_E_NONE; 10113 } 10114 10115 10116 /* 10117 * Function: 10118 * bcm_th3_cosq_cpu_cosq_enable_get 10119 * Purpose: 10120 * To get enable/disable status on Rx of packets on the specified CPU cosq. 10121 * Parameters: 10122 * unit - (IN) Unit number. 10123 * cosq - (IN) CPU Cosq ID 10124 * enable - (OUT) Enable/Disable 10125 * Returns: 10126 * BCM_E_xxx 10127 */ 10128 int 10129 bcm_th3_cosq_cpu_cosq_enable_get(int unit, bcm_cos_queue_t cosq, int *enable) 10130 { 10131 _bcm_th3_cosq_cpu_cosq_config_t *cpu_cosq; 10132 soc_info_t *si; 10133 int index, hw_enable; 10134 uint32 entry[SOC_MAX_MEM_WORDS]; 10135 soc_field_t min_limit, shared_limit, limit_enable, dynamic_enable; 10136 10137 si = &SOC_INFO(unit); 10138 10139 if ((cosq < 0) || (cosq >= NUM_CPU_COSQ(unit))) { 10140 return BCM_E_PARAM; 10141 } 10142 10143 cpu_cosq = _bcm_th3_cosq_cpu_cosq_config[unit][cosq]; 10144 if (!cpu_cosq) { 10145 return BCM_E_INTERNAL; 10146 } 10147 10148 index = si->port_cosq_base[CMIC_PORT(unit)] + cosq; 10149 hw_enable = 1; 10150 10151 /* Sync up software record with hardware status. */ 10152 BCM_IF_ERROR_RETURN(soc_mem_read(unit, MMU_THDO_QUEUE_CONFIGm, MEM_BLOCK_ALL, 10153 index, &entry)); 10154 min_limit = soc_mem_field32_get(unit, MMU_THDO_QUEUE_CONFIGm, &entry, 10155 MIN_LIMITf); 10156 shared_limit = soc_mem_field32_get(unit, MMU_THDO_QUEUE_CONFIGm, &entry, 10157 SHARED_LIMITf); 10158 limit_enable = soc_mem_field32_get(unit, MMU_THDO_QUEUE_CONFIGm, &entry, 10159 LIMIT_ENABLEf); 10160 dynamic_enable = soc_mem_field32_get(unit, MMU_THDO_QUEUE_CONFIGm, &entry, 10161 LIMIT_DYNAMICf); 10162 if ((limit_enable != 0) && (dynamic_enable == 0) && 10163 (min_limit == 0) && (shared_limit == 0)) { 10164 hw_enable = 0; 10165 } 10166 cpu_cosq->enable = hw_enable; 10167 10168 *enable = cpu_cosq->enable; 10169 return BCM_E_NONE; 10170 } 10171 10172 /* 10173 * Function: 10174 * bcm_th3_cosq_buffer_id_multi_get 10175 * Purpose: 10176 * Get mutliple buffer ids associated with a specified port. 10177 * Parameters: 10178 * unit - (IN) BCM device number. 10179 * gport - (IN) Port 10180 * cosq - (IN) Reserved field 10181 * direction - (IN) Specify ingress or egress direction 10182 * array_max - (IN) number of entries to be retrieved 10183 * buf_id_array - (OUT) Buffer id array 10184 * array_count - (OUT) Actural buffer id count in buf_id_array 10185 * Returns: 10186 * BCM_E_XXX 10187 */ 10188 int 10189 bcm_th3_cosq_buffer_id_multi_get(int unit, bcm_gport_t gport, 10190 bcm_cos_queue_t cosq, bcm_cosq_dir_t direction, 10191 int array_max, bcm_cosq_buffer_id_t *buf_id_array, 10192 int *array_count) 10193 { 10194 bcm_port_t local_port; 10195 int pipe, i, idx; 10196 int itm_map; 10197 int itm; 10198 int ibuf_arr[_TH3_ITMS_PER_DEV] = {0}; 10199 int ebuf_arr[_TH3_ITMS_PER_DEV] = {0}; 10200 10201 if ((direction < bcmCosqIngress) || 10202 (direction >= bcmCosqDirectionMaxCount)) { 10203 return BCM_E_PARAM; 10204 } 10205 10206 if (buf_id_array == NULL) { 10207 return BCM_E_PARAM; 10208 } 10209 10210 if (array_count == NULL) { 10211 return BCM_E_PARAM; 10212 } 10213 10214 if (!BCM_GPORT_IS_SET(gport)) { 10215 local_port = gport; 10216 } else if (BCM_GPORT_IS_LOCAL(gport)) { 10217 local_port = BCM_GPORT_LOCAL_GET(gport); 10218 } else if (BCM_GPORT_IS_MODPORT(gport)) { 10219 BCM_IF_ERROR_RETURN(bcm_esw_port_local_get(unit, gport, &local_port)); 10220 } else if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 10221 BCM_IF_ERROR_RETURN(_bcm_th3_cosq_index_resolve(unit, gport, cosq, 10222 _BCM_TH3_COSQ_INDEX_STYLE_UCAST_QUEUE, &local_port, &idx, NULL)); 10223 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 10224 BCM_IF_ERROR_RETURN(_bcm_th3_cosq_index_resolve(unit, gport, cosq, 10225 _BCM_TH3_COSQ_INDEX_STYLE_MCAST_QUEUE, &local_port, &idx, NULL)); 10226 } else { 10227 return BCM_E_PARAM; 10228 } 10229 10230 if (!SOC_PORT_VALID(unit, local_port)) { 10231 return BCM_E_PORT; 10232 } 10233 10234 SOC_IF_ERROR_RETURN(soc_port_pipe_get(unit, local_port, &pipe)); 10235 10236 if (array_max <= 0) { 10237 return BCM_E_PARAM; 10238 } else { 10239 *array_count = (direction == bcmCosqIngress) ? 1 : 10240 MIN(array_max, NUM_ITM(unit)); 10241 } 10242 10243 itm_map = SOC_INFO(unit).ipipe_itm_map[pipe]; 10244 idx = 0; 10245 for (itm = 0; itm < NUM_ITM(unit); itm++) { 10246 ebuf_arr[itm] = itm; 10247 if (itm_map & (1 << itm)) { 10248 ibuf_arr[idx] = itm; 10249 idx++; 10250 } 10251 } 10252 10253 for (i = 0; i < *array_count; i++) { 10254 if (bcmCosqIngress == direction) { 10255 buf_id_array[i] = ibuf_arr[i]; 10256 } else { 10257 buf_id_array[i] = ebuf_arr[i]; 10258 } 10259 } 10260 for (i = *array_count; i < array_max; i++) { 10261 buf_id_array[i] = BCM_COSQ_INVALID_BUF_ID; 10262 } 10263 10264 return BCM_E_NONE; 10265 } 10266 10267 int bcm_th3_cosq_burst_monitor_dma_config_reset(int unit) 10268 { 10269 uint32 qcm_app_status[2], qcm_host_status, qcm_uc_status, time_count; 10270 uint32 *read_addr_ptr, read_addr; 10271 10272 qcm_app_status[0] = soc_uc_mem_read(unit, (SRAM_BASEADDR(unit) + sram_offset(app_status))); 10273 qcm_app_status[1] = soc_uc_mem_read(unit, (SRAM_BASEADDR(unit) + sram_offset(app_status) + 4)); 10274 10275 /* Validation check whether core 0 R5 is loaded with CM app srec file 10276 * ASCII of word QCM_(SHR_QCM_APP_STATUS_1) and _APP(SHR_QCM_APP_STATUS_2) 10277 */ 10278 if ((qcm_app_status[0] != SHR_QCM_APP_STATUS_1) || 10279 (qcm_app_status[1] != SHR_QCM_APP_STATUS_2)) { 10280 LOG_ERROR(BSL_LS_BCM_COSQ, (BSL_META_U(unit, 10281 "load CM APP srec file to core 0\n"))); 10282 return BCM_E_UNAVAIL; 10283 } 10284 10285 qcm_host_status = soc_uc_mem_read(unit, (SRAM_BASEADDR(unit) + sram_offset(host_status))); 10286 if (!(qcm_host_status & SHR_QCM_INIT_STATUS_BIT)) { 10287 LOG_ERROR(BSL_LS_BCM_COSQ, (BSL_META_U(unit, 10288 "shared memory not allocated yet\n"))); 10289 return BCM_E_INIT; 10290 } 10291 read_addr = soc_uc_mem_read(unit, (SRAM_BASEADDR(unit) + sram_offset(host_buf_start_addr))); 10292 read_addr_ptr = (uint32 *)soc_cm_p2l(unit, read_addr); 10293 10294 qcm_host_status = (qcm_host_status & (~SHR_QCM_INIT_STATUS_BIT)); 10295 soc_uc_mem_write(unit, (SRAM_BASEADDR(unit) + sram_offset(host_status)), (uint32)qcm_host_status); 10296 10297 time_count = 0; 10298 while (1) { 10299 qcm_uc_status = soc_uc_mem_read(unit, (SRAM_BASEADDR(unit) + sram_offset(uc_status))); 10300 qcm_uc_status = qcm_uc_status & SHR_QCM_INIT_STATUS_BIT; 10301 if (!qcm_uc_status) { 10302 break; 10303 } 10304 ++time_count; 10305 if ((time_count * QCM_UC_STATUS_TIMEOUT) > QCM_UC_MSG_TIMEOUT) { 10306 LOG_ERROR(BSL_LS_BCM_COSQ, (BSL_META_U(unit, 10307 "CM APP R5 core 0 does not responded\n"))); 10308 return BCM_E_TIMEOUT; 10309 } 10310 sal_usleep(QCM_UC_STATUS_TIMEOUT); 10311 } 10312 soc_cm_sfree(unit, read_addr_ptr); 10313 10314 return BCM_E_NONE; 10315 } 10316 10317 int bcm_th3_cosq_burst_monitor_dma_config_set(int unit, 10318 uint32 host_mem_size, 10319 uint32 **host_mem_add) 10320 { 10321 uint32 qcm_app_status[2], qcm_host_status, qcm_uc_status, shared_mem_size, share_mem_add, endianess; 10322 int time_count, rv; 10323 10324 qcm_app_status[0] = soc_uc_mem_read(unit, (SRAM_BASEADDR(unit) + sram_offset(app_status))); 10325 qcm_app_status[1] = soc_uc_mem_read(unit, (SRAM_BASEADDR(unit) + sram_offset(app_status) + 4)); 10326 10327 /* Validation check whether core 0 R5 is loaded with QCM app srec file 10328 * ASCII of word QCM_(SHR_QCM_APP_STATUS_1) and _APP(SHR_QCM_APP_STATUS_2) 10329 */ 10330 if ((qcm_app_status[0] != SHR_QCM_APP_STATUS_1) || 10331 (qcm_app_status[1] != SHR_QCM_APP_STATUS_2)) { 10332 LOG_ERROR(BSL_LS_BCM_COSQ, (BSL_META_U(unit, 10333 "load QCM app srec file to core 0\n"))); 10334 return BCM_E_UNAVAIL; 10335 } 10336 10337 qcm_host_status = soc_uc_mem_read(unit, (SRAM_BASEADDR(unit) + sram_offset(host_status))); 10338 if (qcm_host_status & SHR_QCM_INIT_STATUS_BIT) { 10339 if (host_mem_size == 0) { 10340 rv = bcm_th3_cosq_burst_monitor_dma_config_reset(unit); 10341 *host_mem_add = NULL; 10342 soc_uc_mem_write(unit, (SRAM_BASEADDR(unit) + sram_offset(host_buf_start_addr)), (uint32)0); 10343 soc_uc_mem_write(unit, (SRAM_BASEADDR(unit) + sram_offset(host_buf_size)), (uint32)0); 10344 return rv; 10345 } else { 10346 LOG_ERROR(BSL_LS_BCM_COSQ, (BSL_META_U(unit, 10347 "already configured\n"))); 10348 return BCM_E_PARAM; 10349 } 10350 } 10351 10352 qcm_host_status = qcm_host_status | SHR_QCM_INIT_STATUS_BIT; 10353 shared_mem_size = (uint32)sizeof(struct bcm_cosq_burst_output_s); 10354 shared_mem_size = host_mem_size - (host_mem_size % shared_mem_size); 10355 10356 if (shared_mem_size < SHR_QCM_MEM_MIN_SIZE) { 10357 LOG_ERROR(BSL_LS_BCM_COSQ, (BSL_META_U(unit, 10358 "except's minimum shared memory size : %x\n"), 10359 SHR_QCM_MEM_MIN_SIZE)); 10360 return BCM_E_PARAM; 10361 } 10362 10363 /* Ensure QCM app host memory is not NULL */ 10364 *host_mem_add = (uint32 *) soc_cm_salloc(unit, host_mem_size, "Host buffer"); 10365 if (*host_mem_add == NULL) { 10366 LOG_ERROR(BSL_LS_BCM_COSQ, (BSL_META_U(unit, 10367 "host memory address NULL\n"))); 10368 return BCM_E_PARAM; 10369 } 10370 10371 sal_memset(*host_mem_add, 0, host_mem_size); 10372 share_mem_add = (uint32)soc_cm_l2p(unit, *host_mem_add); 10373 10374 soc_uc_mem_write(unit, (SRAM_BASEADDR(unit) + sram_offset(host_buf_start_addr)), (uint32)share_mem_add); 10375 soc_uc_mem_write(unit, (SRAM_BASEADDR(unit) + sram_offset(host_buf_size)), (uint32)shared_mem_size); 10376 10377 10378 soc_uc_mem_write(unit, (SRAM_BASEADDR(unit) + sram_offset(host_status)), (uint32)qcm_host_status); 10379 10380 time_count = 0; 10381 while (1) { 10382 qcm_uc_status = soc_uc_mem_read(unit, (SRAM_BASEADDR(unit) + sram_offset(uc_status))); 10383 qcm_uc_status = qcm_uc_status & SHR_QCM_INIT_STATUS_BIT; 10384 if (qcm_host_status == qcm_uc_status) { 10385 break; 10386 } 10387 ++time_count; 10388 if ((time_count * QCM_UC_STATUS_TIMEOUT) > QCM_UC_MSG_TIMEOUT) { 10389 LOG_ERROR(BSL_LS_BCM_COSQ, (BSL_META_U(unit, 10390 "QCM app R5 core 0 does not responded\n"))); 10391 return BCM_E_TIMEOUT; 10392 } 10393 sal_usleep(QCM_UC_STATUS_TIMEOUT); 10394 } 10395 if (*host_mem_add[0] == 0x1000000) { 10396 endianess = 1; 10397 } else { 10398 endianess = 0; 10399 } 10400 soc_uc_mem_write(unit, (SRAM_BASEADDR(unit) + sram_offset(endianess)), (uint32)endianess); 10401 10402 return BCM_E_NONE; 10403 } 10404 10405 #ifdef BCM_WARM_BOOT_SUPPORT 10406 STATIC int 10407 _bcm_th3_cosq_rx_queue_channel_reinit(int unit) 10408 { 10409 _bcm_th3_cosq_cpu_port_info_t *cpu_port_info = NULL; 10410 int idx; 10411 /* 10412 * L0.0 is associated with CMC0 CH1(Rx) 10413 * L0.1 is associated with CMC0 CH2(Rx) 10414 * L0.2 is associated with CMC0 CH3(Rx) 10415 * L0.3 is associated with CMC0 CH4(Rx) 10416 * L0.4 is associated with CMC0 CH5(Rx) 10417 * L0.5 is associated with CMC0 CH6(Rx) 10418 * L0.6 is associated with CMC0 CH7(Rx) 10419 */ 10420 bcm_gport_t sched_gport[7]; 10421 bcm_cos_queue_t parent_cos; 10422 10423 cpu_port_info = _bcm_th3_cosq_cpu_port_info[unit]; 10424 if (cpu_port_info == NULL) { 10425 return BCM_E_INIT; 10426 } 10427 10428 for (idx = 0; idx < 7; idx++) { 10429 sched_gport[idx] = cpu_port_info->sched[idx].gport; 10430 } 10431 10432 for (idx = 0; idx < _BCM_TH3_NUM_CPU_MCAST_QUEUE; idx++) { 10433 parent_cos = -1; 10434 if (cpu_port_info->mcast[idx].parent_gport == sched_gport[0]) { 10435 parent_cos = 0; 10436 } else if (cpu_port_info->mcast[idx].parent_gport == sched_gport[1]) { 10437 parent_cos = 1; 10438 } else if (cpu_port_info->mcast[idx].parent_gport == sched_gport[2]) { 10439 parent_cos = 2; 10440 } else if (cpu_port_info->mcast[idx].parent_gport == sched_gport[3]) { 10441 parent_cos = 3; 10442 } else if (cpu_port_info->mcast[idx].parent_gport == sched_gport[4]) { 10443 parent_cos = 4; 10444 } else if (cpu_port_info->mcast[idx].parent_gport == sched_gport[5]) { 10445 parent_cos = 5; 10446 } else if (cpu_port_info->mcast[idx].parent_gport == sched_gport[6]) { 10447 parent_cos = 6; 10448 } 10449 if ((parent_cos >= 0) && (parent_cos < 7)) { 10450 BCM_IF_ERROR_RETURN 10451 (_bcm_th3_cosq_rx_queue_channel_set(unit, parent_cos, idx, 1)); 10452 } 10453 } 10454 return BCM_E_NONE; 10455 } 10456 #endif /* BCM_WARM_BOOT_SUPPORT */ 10457 10458 10459 #ifdef BCM_WARM_BOOT_SUPPORT 10460 int 10461 bcm_th3_cosq_reinit(int unit) 10462 { 10463 soc_scache_handle_t scache_handle; 10464 uint8 *scache_ptr = NULL; 10465 int *int_scache_ptr = NULL; 10466 uint16 *u16_scache_ptr = NULL; 10467 uint32 *u32_scache_ptr = NULL; 10468 _bcm_th3_mmu_info_t *mmu_info = NULL; 10469 _bcm_th3_cosq_cpu_port_info_t *cpu_port_info = NULL; 10470 int alloc_size = 0, i, j, pipe = -1, itm; 10471 soc_profile_mem_t *profile_mem; 10472 soc_mem_t wred_config_mem = INVALIDm; 10473 int index, profile_index, resolution_index; 10474 int stable_size, rv, num, set_index; 10475 mmu_wred_config_entry_t *qentry; 10476 uint8 * mmu_wred_config_buf[8][2]; 10477 uint32 entry[SOC_MAX_MEM_WORDS]; 10478 bcm_port_t port; 10479 _bcm_bst_device_handlers_t bst_callbks; 10480 10481 _bcm_th3_cosq_cpu_cosq_config_t *cpu_cosq_config_p; 10482 uint16 recovered_ver = 0; 10483 int index_min, index_max; 10484 int additional_scache_sz = 0; 10485 int profile_idx, qidx; 10486 uint32 qcm_app_status[2], host_mem_size; 10487 uint32 *host_mem_add; 10488 uint32 pipe_map; 10489 int ii; 10490 int itm_map; 10491 uint16 dev_id; 10492 uint8 rev_id; 10493 10494 soc_cm_get_id(unit, &dev_id, &rev_id); 10495 itm_map = SOC_INFO(unit).itm_map; 10496 10497 SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size)); 10498 if ((stable_size == 0) || (SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit))) { 10499 /* COSQ warmboot requires extended scache support i.e. level2 warmboot*/ 10500 return BCM_E_NONE; 10501 } 10502 10503 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 0); 10504 rv = _bcm_esw_scache_ptr_get(unit, scache_handle, FALSE, 0, &scache_ptr, 10505 BCM_WB_DEFAULT_VERSION, &recovered_ver); 10506 if (BCM_FAILURE(rv)) { 10507 return rv; 10508 } 10509 10510 mmu_info = _bcm_th3_mmu_info[unit]; 10511 10512 if (mmu_info == NULL) { 10513 return BCM_E_INIT; 10514 } 10515 10516 cpu_port_info = _bcm_th3_cosq_cpu_port_info[unit]; 10517 if (cpu_port_info == NULL) { 10518 return BCM_E_INIT; 10519 } 10520 10521 /* Update mmu_info shared limit parameters */ 10522 int_scache_ptr = (int *) scache_ptr; 10523 /* shared limits are now recovered from hw */ 10524 int_scache_ptr += 1; 10525 BCM_IF_ERROR_RETURN( 10526 soc_th3_mmu_get_shared_size(unit, 10527 mmu_info->shared_limit)); 10528 10529 alloc_size = sizeof(_bcm_th3_cosq_cpu_port_info_t); 10530 scache_ptr = (uint8*) int_scache_ptr; 10531 sal_memcpy(cpu_port_info, scache_ptr, alloc_size); 10532 10533 /* Restore the Queue to Channel Mapping */ 10534 BCM_IF_ERROR_RETURN 10535 (_bcm_th3_cosq_rx_queue_channel_reinit(unit)); 10536 10537 scache_ptr += alloc_size; 10538 10539 /* Update IFP_COS_MAP memory profile reference counter */ 10540 profile_mem = _bcm_th3_ifp_cos_map_profile[unit]; 10541 num = SOC_MEM_SIZE(unit, IFP_COS_MAPm) / _TH3_MMU_NUM_INT_PRI - 1; 10542 u16_scache_ptr = (uint16 *)scache_ptr; 10543 for (i = 0; i < num; i++) { 10544 for (j = 0; j < *u16_scache_ptr; j++) { 10545 SOC_IF_ERROR_RETURN( 10546 soc_profile_mem_reference(unit, profile_mem, 10547 i * _TH3_MMU_NUM_INT_PRI, 10548 _TH3_MMU_NUM_INT_PRI)); 10549 } 10550 u16_scache_ptr++; 10551 } 10552 10553 /* Recover CPU queue config information from scache */ 10554 cpu_cosq_config_p = _bcm_th3_cosq_cpu_cosq_config[unit][0]; 10555 if (cpu_cosq_config_p == NULL) { 10556 return BCM_E_INIT; 10557 } 10558 alloc_size = (SOC_TH3_NUM_CPU_QUEUES * 10559 sizeof(_bcm_th3_cosq_cpu_cosq_config_t)); 10560 scache_ptr = (uint8*) u16_scache_ptr; 10561 sal_memcpy(cpu_cosq_config_p, scache_ptr, alloc_size); 10562 scache_ptr += alloc_size; 10563 10564 /* Retriving num_cos value */ 10565 int_scache_ptr = (int *) scache_ptr; 10566 _TH3_NUM_COS(unit) = *int_scache_ptr++; 10567 scache_ptr = (uint8*) int_scache_ptr; 10568 10569 /* 10570 * Retriving th3_sched_profile_info struture for all scheduler profiles 10571 * size = sizeof(soc_th3_sched_profile_info_t) * SOC_TH3_MAX_NUM_SCHED_PROFILE * SOC_TH3_NUM_GP_QUEUES; 10572 */ 10573 int_scache_ptr = (int*) scache_ptr; 10574 for (profile_idx = 0; profile_idx < SOC_TH3_MAX_NUM_SCHED_PROFILE; profile_idx++) { 10575 for (qidx = 0; qidx < SOC_TH3_NUM_GP_QUEUES; qidx++) { 10576 th3_sched_profile_info[unit][profile_idx][qidx].cos = *int_scache_ptr++; 10577 th3_sched_profile_info[unit][profile_idx][qidx].mmuq[0] = *int_scache_ptr++; 10578 th3_sched_profile_info[unit][profile_idx][qidx].mmuq[1] = *int_scache_ptr++; 10579 th3_sched_profile_info[unit][profile_idx][qidx].strict_priority = *int_scache_ptr++; 10580 th3_sched_profile_info[unit][profile_idx][qidx].fc_is_uc_only = *int_scache_ptr++; 10581 } 10582 } 10583 scache_ptr = (uint8 *)int_scache_ptr; 10584 10585 BCM_IF_ERROR_RETURN(_bcm_th3_cosq_scheduler_reinit(unit)); 10586 10587 /* PFC Deadlock recovery should be initialized 10588 irrespective of scache version to handle 10589 upgrades. */ 10590 if (soc_feature(unit, soc_feature_pfc_deadlock)) { 10591 BCM_IF_ERROR_RETURN(_bcm_th3_pfc_deadlock_init(unit)); 10592 BCM_IF_ERROR_RETURN(_bcm_th3_pfc_deadlock_reinit(unit, &scache_ptr)); 10593 BCM_IF_ERROR_RETURN(_bcm_th3_pfc_deadlock_recovery_reset(unit)); 10594 } 10595 10596 /* Update PRIO2COS_PROFILE register profile reference counter */ 10597 10598 10599 /* Update PORT_COS_MAP memory profile reference counter */ 10600 profile_mem = _bcm_th3_cos_map_profile[unit]; 10601 PBMP_ALL_ITER(unit, port) { 10602 SOC_IF_ERROR_RETURN 10603 (soc_mem_read(unit, COS_MAP_SELm, MEM_BLOCK_ALL, port, &entry)); 10604 set_index = soc_mem_field32_get(unit, COS_MAP_SELm, &entry, SELECTf); 10605 SOC_IF_ERROR_RETURN 10606 (soc_profile_mem_reference(unit, profile_mem, set_index * _TH3_MMU_NUM_INT_PRI, 10607 _TH3_MMU_NUM_INT_PRI)); 10608 } 10609 if (SOC_INFO(unit).cpu_hg_index != -1) { 10610 SOC_IF_ERROR_RETURN(soc_mem_read(unit, COS_MAP_SELm, MEM_BLOCK_ALL, 10611 SOC_INFO(unit).cpu_hg_index, &entry)); 10612 set_index = soc_mem_field32_get(unit, COS_MAP_SELm, &entry, SELECTf); 10613 SOC_IF_ERROR_RETURN 10614 (soc_profile_mem_reference(unit, profile_mem, set_index * _TH3_MMU_NUM_INT_PRI, 10615 _TH3_MMU_NUM_INT_PRI)); 10616 } 10617 10618 index_min = soc_mem_index_min(unit, MMU_WRED_QUEUE_CONFIGm); 10619 index_max = soc_mem_index_max(unit, MMU_WRED_QUEUE_CONFIGm); 10620 /* index_max = soc_mem_index_max(unit, SOC_MEM_UNIQUE_ACC_ITM_PIPE(unit, 10621 MMU_WRED_QUEUE_CONFIGm, 0, 0));*/ 10622 10623 wred_config_mem = MMU_WRED_QUEUE_CONFIGm; 10624 10625 soc_tomahawk3_pipe_map_get(unit, &pipe_map); 10626 for (pipe = 0; pipe < NUM_PIPE(unit); pipe++) { 10627 if (!(pipe_map & (1 << pipe))) { 10628 continue; 10629 } 10630 for (itm = 0; itm < SOC_MMU_CFG_ITM_MAX; itm++) { 10631 if (!(itm_map & 1 << itm)) { 10632 continue; 10633 } 10634 mmu_wred_config_buf[pipe][itm] = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES(unit, 10635 wred_config_mem), 10636 "mmu_wred"); 10637 BCM_IF_ERROR_RETURN 10638 (soc_tomahawk3_itm_mem_read_range(unit, wred_config_mem, 10639 itm, pipe, MEM_BLOCK_ALL, index_min, index_max, mmu_wred_config_buf[pipe][itm])); 10640 } 10641 } 10642 10643 for (pipe = 0; pipe < NUM_PIPE(unit); pipe++) { 10644 for (itm = 0; itm < SOC_MMU_CFG_ITM_MAX; itm++) { 10645 if (!(itm_map & 1 << itm)) { 10646 continue; 10647 } 10648 if (pipe_map & (1 << pipe)) { 10649 for (index = index_min; index < index_max; index++) { 10650 10651 qentry = soc_mem_table_idx_to_pointer(unit, wred_config_mem, mmu_wred_config_entry_t *, 10652 mmu_wred_config_buf[pipe][itm], index); 10653 10654 profile_index = soc_mem_field32_get(unit, wred_config_mem, 10655 qentry, PROFILE_INDEXf); 10656 rv = (soc_profile_mem_reference 10657 (unit, _bcm_th3_wred_profile[unit], profile_index, 1)); 10658 10659 if (SOC_FAILURE(rv)) { 10660 goto cleanup; 10661 } 10662 10663 if (soc_mem_field32_get(unit, wred_config_mem, qentry, 10664 ECN_MARKING_ENf)) { 10665 resolution_index = soc_mem_field32_get( 10666 unit, wred_config_mem, qentry, 10667 WRED_CONG_NOTIFICATION_RESOLUTION_TABLE_MARKING_INDEXf); 10668 } else { 10669 resolution_index = soc_mem_field32_get( 10670 unit, wred_config_mem, qentry, 10671 WRED_CONG_NOTIFICATION_RESOLUTION_TABLE_DROPPING_INDEXf); 10672 } 10673 _bcm_th3_wred_resolution_tbl[resolution_index] = 1; 10674 } 10675 } 10676 } 10677 } 10678 cleanup: 10679 for (pipe = 0; pipe < NUM_PIPE(unit); pipe++) { 10680 if (!(pipe_map & (1 << pipe))) { 10681 continue; 10682 } 10683 for (itm = 0; itm < SOC_MMU_CFG_ITM_MAX; itm++) { 10684 if (!(itm_map & 1 << itm)) { 10685 continue; 10686 } 10687 if (mmu_wred_config_buf[pipe][itm]) { 10688 soc_cm_sfree(unit, mmu_wred_config_buf[pipe][itm]); 10689 mmu_wred_config_buf[pipe][itm] = NULL; 10690 } 10691 } 10692 } 10693 if (SOC_FAILURE(rv)) { 10694 return rv; 10695 } 10696 10697 /* Create gport tree */ 10698 _BCM_TH3_MMU_INFO(unit)->gport_tree_created = FALSE; 10699 PBMP_ALL_ITER(unit, port) { 10700 if (IS_LB_PORT(unit, port) || IS_CPU_PORT(unit, port)) { 10701 continue; 10702 } 10703 BCM_IF_ERROR_RETURN 10704 (_bcm_th3_cosq_gport_tree_create(unit, port)); 10705 } 10706 10707 _BCM_TH3_MMU_INFO(unit)->gport_tree_created = TRUE; 10708 10709 /* BST reinit */ 10710 10711 sal_memset(&bst_callbks, 0, sizeof(_bcm_bst_device_handlers_t)); 10712 bst_callbks.resolve_index = &bcm_bst_th3_index_resolve; 10713 bst_callbks.reverse_resolve_index = NULL; 10714 10715 BCM_IF_ERROR_RETURN(_bcm_bst_attach(unit, &bst_callbks)); 10716 10717 #if defined(INCLUDE_PSTATS) 10718 if (soc_feature(unit, soc_feature_pstats)) { 10719 rv = _bcm_pstats_init(unit); 10720 if (rv != BCM_E_NONE) { 10721 if (cpu_cosq_config_p != NULL) { 10722 sal_free(cpu_cosq_config_p); 10723 cpu_cosq_config_p = NULL; 10724 } 10725 _bcm_th3_cosq_cleanup(unit); 10726 return rv; 10727 } 10728 } 10729 #endif /* INCLUDE_PSTATS */ 10730 10731 /* Recovery TIME_DOMAINr count reference */ 10732 for (ii = 0; ii < _BCM_TH3_NUM_TIME_DOMAIN; ii++) { 10733 alloc_size = sizeof(uint32); 10734 sal_memcpy(&th3_time_domain_info[unit][ii].ref_count, scache_ptr, alloc_size); 10735 scache_ptr += alloc_size; 10736 } 10737 10738 #ifdef BCM_TOMAHAWK3_SUPPORT 10739 if (soc_feature(unit, soc_feature_ecn_wred)) { 10740 BCM_IF_ERROR_RETURN(bcmi_xgs5_ecn_reinit(unit, &scache_ptr)); 10741 } 10742 #endif 10743 10744 10745 /* Retriving _bcm_th3_wred_resolution_tbl value */ 10746 u32_scache_ptr = (uint32 *) scache_ptr; 10747 for (i = 0; i < _BCM_TH3_NUM_WRED_RESOLUTION_TABLE; i++) { 10748 _bcm_th3_wred_resolution_tbl[i] = *u32_scache_ptr++; 10749 } 10750 10751 /* realloc scache_handle resource*/ 10752 if (additional_scache_sz != 0) { 10753 rv = soc_scache_realloc(unit, scache_handle, additional_scache_sz); 10754 if (SOC_FAILURE(rv)) { 10755 return rv; 10756 } 10757 } 10758 10759 qcm_app_status[0] = soc_uc_mem_read(unit, (SRAM_BASEADDR(unit) + sram_offset(app_status))); 10760 qcm_app_status[1] = soc_uc_mem_read(unit, (SRAM_BASEADDR(unit) + sram_offset(app_status) + 4)); 10761 10762 /* Validation check whether core 0 R5 is loaded with QCM app srec file 10763 * ASCII of word QCM_(SHR_QCM_APP_STATUS_1) and _APP(SHR_QCM_APP_STATUS_2) 10764 */ 10765 if ((qcm_app_status[0] == SHR_QCM_APP_STATUS_1) && 10766 (qcm_app_status[1] == SHR_QCM_APP_STATUS_2)) { 10767 host_mem_size = soc_uc_mem_read(unit, (SRAM_BASEADDR(unit) + sram_offset(host_buf_size))); 10768 if (host_mem_size >= SHR_QCM_MEM_MIN_SIZE) { 10769 bcm_th3_cosq_burst_monitor_dma_config_set(unit, host_mem_size, &host_mem_add); 10770 } 10771 } 10772 10773 return BCM_E_NONE; 10774 } 10775 10776 int 10777 bcm_th3_cosq_sync(int unit) 10778 { 10779 soc_scache_handle_t scache_handle; 10780 uint8 *scache_ptr; 10781 uint32 *u32_scache_ptr; 10782 uint16 *u16_scache_ptr; 10783 int *int_scache_ptr; 10784 _bcm_th3_mmu_info_t *mmu_info = NULL; 10785 _bcm_th3_cosq_cpu_port_info_t *cpu_port_info = NULL; 10786 int size = 0, ii; 10787 int shared_limit_min; 10788 int itm_map; 10789 int rv = BCM_E_NONE, ref_count, val = 0, pri, port; 10790 _bcm_th3_cosq_cpu_cosq_config_t **cpu_cosq_config_p; 10791 int profile_idx, qidx; 10792 uint32 qcm_app_status[2], qcm_host_status; 10793 10794 mmu_info = _bcm_th3_mmu_info[unit]; 10795 if (mmu_info == NULL) { 10796 return BCM_E_INIT; 10797 } 10798 10799 cpu_port_info = _bcm_th3_cosq_cpu_port_info[unit]; 10800 if (cpu_port_info == NULL) { 10801 return BCM_E_INIT; 10802 } 10803 10804 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 0); 10805 BCM_IF_ERROR_RETURN 10806 (_bcm_esw_scache_ptr_get(unit, scache_handle, FALSE, 0, 10807 &scache_ptr, BCM_WB_DEFAULT_VERSION, NULL)); 10808 10809 /* Cache minimal ing_shared_limit/egr_db_shared_limit/egr_qe_shared_limit */ 10810 itm_map = SOC_INFO(unit).itm_map; 10811 _TH3_ARRAY_MIN(_BCM_TH3_MMU_INFO(unit)->shared_limit, NUM_ITM(unit), 10812 itm_map, shared_limit_min); 10813 u32_scache_ptr = (uint32*) scache_ptr; 10814 *u32_scache_ptr++ = shared_limit_min; 10815 10816 /* Cache _bcm_th3_cosq_cpu_port_info_t structure */ 10817 size = sizeof(_bcm_th3_cosq_cpu_port_info_t); 10818 scache_ptr = (uint8*)u32_scache_ptr; 10819 sal_memcpy(scache_ptr, cpu_port_info, size); 10820 scache_ptr += size/sizeof(uint8); 10821 10822 /* Cache _bcm_th3_ifp_cos_map_profile reference count */ 10823 u16_scache_ptr = (uint16 *)scache_ptr; 10824 for (ii = 0; 10825 ii < ((SOC_MEM_SIZE(unit, IFP_COS_MAPm) / _TH3_MMU_NUM_INT_PRI) - 1); 10826 ii++) { 10827 rv = soc_profile_mem_ref_count_get(unit, 10828 _bcm_th3_ifp_cos_map_profile[unit], 10829 ii * _TH3_MMU_NUM_INT_PRI, 10830 &ref_count); 10831 if (!(rv == SOC_E_NOT_FOUND || rv == SOC_E_NONE)) { 10832 return rv; 10833 } 10834 *u16_scache_ptr++ = (uint16)(ref_count & 0xffff); 10835 } 10836 10837 /* Sync CPU Queue info */ 10838 cpu_cosq_config_p = _bcm_th3_cosq_cpu_cosq_config[unit]; 10839 size = (SOC_TH3_NUM_CPU_QUEUES * sizeof(_bcm_th3_cosq_cpu_cosq_config_t)); 10840 scache_ptr = (uint8*) u16_scache_ptr; 10841 sal_memcpy(scache_ptr, *cpu_cosq_config_p, size); 10842 scache_ptr += (size / sizeof(uint8)); 10843 10844 /* Sync num_cos value */ 10845 int_scache_ptr = (int*) scache_ptr; 10846 *int_scache_ptr++ = _TH3_NUM_COS(unit); 10847 scache_ptr = (uint8 *)int_scache_ptr; 10848 10849 /* 10850 * Sync th3_sched_profile_info struture for all scheduler profiles 10851 * size = sizeof(soc_th3_sched_profile_info_t) * SOC_TH3_MAX_NUM_SCHED_PROFILE * SOC_TH3_NUM_GP_QUEUES; 10852 */ 10853 int_scache_ptr = (int*) scache_ptr; 10854 for (profile_idx = 0; profile_idx < SOC_TH3_MAX_NUM_SCHED_PROFILE; profile_idx++) { 10855 for (qidx = 0; qidx < SOC_TH3_NUM_GP_QUEUES; qidx++) { 10856 *int_scache_ptr++ = th3_sched_profile_info[unit][profile_idx][qidx].cos; 10857 *int_scache_ptr++ = th3_sched_profile_info[unit][profile_idx][qidx].mmuq[0]; 10858 *int_scache_ptr++ = th3_sched_profile_info[unit][profile_idx][qidx].mmuq[1]; 10859 *int_scache_ptr++ = th3_sched_profile_info[unit][profile_idx][qidx].strict_priority; 10860 *int_scache_ptr++ = th3_sched_profile_info[unit][profile_idx][qidx].fc_is_uc_only; 10861 } 10862 } 10863 scache_ptr = (uint8 *)int_scache_ptr; 10864 10865 /* Sync PFC deadlock recovery timer period. */ 10866 if (soc_feature(unit, soc_feature_pfc_deadlock)) { 10867 u16_scache_ptr = (uint16 *)scache_ptr; 10868 for (port = 0; port < SOC_MAX_NUM_PORTS; port++) { 10869 for (pri = 0; pri < TH3_PFC_PRIORITY_NUM; pri++) { 10870 if (bcm_tomahawk3_cosq_pfc_deadlock_control_get(unit, 10871 port, pri, 10872 bcmCosqPFCDeadlockRecoveryTimer, 10873 &val) == BCM_E_NONE) { 10874 *u16_scache_ptr++ = (uint16) val; 10875 } else { 10876 *u16_scache_ptr++ = 0; 10877 } 10878 } 10879 } 10880 } 10881 scache_ptr = (uint8*)u16_scache_ptr; 10882 u32_scache_ptr = (uint32*) scache_ptr; 10883 10884 if (soc_feature(unit, soc_feature_pfc_deadlock)) { 10885 u32_scache_ptr = (uint32 *)scache_ptr; 10886 for (port = 0; port < SOC_MAX_NUM_PORTS; port++) { 10887 for (pri = 0; pri < TH3_PFC_PRIORITY_NUM; pri++) { 10888 if (bcm_tomahawk3_cosq_pfc_deadlock_control_get(unit, 10889 port, pri, 10890 bcmCosqPFCDeadlockRecoveryOccurrences, 10891 &val) == BCM_E_NONE) { 10892 *u32_scache_ptr++ = val; 10893 } else { 10894 *u32_scache_ptr++ = 0; 10895 } 10896 } 10897 } 10898 } 10899 scache_ptr = (uint8*)u32_scache_ptr; 10900 10901 /* Sync TIME_DOMAINr field and count reference */ 10902 u32_scache_ptr = (uint32*) scache_ptr; 10903 size = sizeof(uint32); 10904 for (ii = 0; ii < _BCM_TH3_NUM_TIME_DOMAIN; ii++) { 10905 sal_memcpy(u32_scache_ptr, &th3_time_domain_info[unit][ii].ref_count, size); 10906 u32_scache_ptr++; 10907 } 10908 10909 scache_ptr = (uint8*)u32_scache_ptr; 10910 #ifdef BCM_TOMAHAWK3_SUPPORT 10911 if (soc_feature(unit, soc_feature_ecn_wred)) { 10912 BCM_IF_ERROR_RETURN(bcmi_xgs5_ecn_sync(unit, &scache_ptr)); 10913 } 10914 #endif 10915 10916 u32_scache_ptr = (uint32*) scache_ptr; 10917 for (ii = 0; ii < _BCM_TH3_NUM_WRED_RESOLUTION_TABLE; ii++) { 10918 *u32_scache_ptr++ = _bcm_th3_wred_resolution_tbl[ii]; 10919 } 10920 scache_ptr = (uint8 *)u32_scache_ptr; 10921 10922 qcm_app_status[0] = soc_uc_mem_read(unit, (SRAM_BASEADDR(unit) + sram_offset(app_status))); 10923 qcm_app_status[1] = soc_uc_mem_read(unit, (SRAM_BASEADDR(unit) + sram_offset(app_status) + 4)); 10924 10925 /* Validation check whether core 0 R5 is loaded with QCM app srec file 10926 * ASCII of word QCM_(SHR_QCM_APP_STATUS_1) and _APP(SHR_QCM_APP_STATUS_2) 10927 */ 10928 if ((qcm_app_status[0] == SHR_QCM_APP_STATUS_1) && 10929 (qcm_app_status[1] == SHR_QCM_APP_STATUS_2)) { 10930 10931 qcm_host_status = soc_uc_mem_read(unit, (SRAM_BASEADDR(unit) + sram_offset(host_status))); 10932 if (qcm_host_status & SHR_QCM_INIT_STATUS_BIT) { 10933 bcm_th3_cosq_burst_monitor_dma_config_reset(unit); 10934 } 10935 } 10936 10937 return BCM_E_NONE; 10938 } 10939 10940 int 10941 _bcm_th3_cosq_scheduler_reinit(int unit) 10942 { 10943 _soc_mmu_cfg_scheduler_profile_t *sched_profile; 10944 int idx, cosq_idx,profile_idx; 10945 int L0[_BCM_TH3_COS_MAX]; 10946 int schedq[_BCM_TH3_COS_MAX]; 10947 int mmuq[_BCM_TH3_COS_MAX]; 10948 int cos_list[_BCM_TH3_COS_MAX]; 10949 int strict_priority[_BCM_TH3_COS_MAX]; 10950 int fc_is_uc_only[_BCM_TH3_COS_MAX]; 10951 int rv = BCM_E_NONE; 10952 10953 sched_profile = soc_mmu_cfg_scheduler_profile_alloc(unit); 10954 10955 for (profile_idx = 0; profile_idx < _BCM_TH3_NUM_QSCHED_PROFILES; profile_idx++) { 10956 cosq_idx = 0; 10957 for (idx = 0; idx < _BCM_TH3_COS_MAX; idx++) { 10958 sched_profile[profile_idx].num_unicast_queue[idx] = 0; 10959 sched_profile[profile_idx].num_multicast_queue[idx] = 0; 10960 sched_profile[profile_idx].strict_priority[idx] = 0; 10961 sched_profile[profile_idx].flow_control_only_unicast[idx] = 0; 10962 } 10963 for (idx = 0; idx < _BCM_TH3_COS_MAX; idx++) { 10964 if (th3_sched_profile_info[unit][profile_idx][idx].cos == -1) { 10965 continue; 10966 } 10967 if (th3_sched_profile_info[unit][profile_idx][idx].mmuq[0] != -1) { 10968 if (th3_sched_profile_info[unit][profile_idx][idx].mmuq[0] < 10969 _bcm_th3_get_num_ucq(unit)) { 10970 sched_profile[profile_idx].num_unicast_queue[cosq_idx]++; 10971 } 10972 else { 10973 sched_profile[profile_idx].num_multicast_queue[cosq_idx]++; 10974 } 10975 10976 } 10977 if (th3_sched_profile_info[unit][profile_idx][idx].mmuq[1] != -1) { 10978 if (th3_sched_profile_info[unit][profile_idx][idx].mmuq[1] < 10979 _bcm_th3_get_num_ucq(unit)) { 10980 sched_profile[profile_idx].num_unicast_queue[cosq_idx]++; 10981 } 10982 else { 10983 sched_profile[profile_idx].num_multicast_queue[cosq_idx]++; 10984 } 10985 10986 } 10987 sched_profile[profile_idx].strict_priority[cosq_idx] = 10988 th3_sched_profile_info[unit][profile_idx][idx].strict_priority; 10989 sched_profile[profile_idx].flow_control_only_unicast[cosq_idx] = 10990 th3_sched_profile_info[unit][profile_idx][idx].fc_is_uc_only; 10991 cosq_idx++; 10992 } 10993 rv = _soc_mmu_tomahawk3_scheduler_profile_config_check(unit, 10994 profile_idx, sched_profile); 10995 10996 if (rv != BCM_E_NONE) { 10997 goto exit; 10998 } 10999 11000 rv = _soc_scheduler_profile_mapping_setup(unit, 11001 sched_profile, profile_idx, L0, schedq, mmuq, cos_list, 11002 strict_priority, fc_is_uc_only); 11003 11004 if (rv != BCM_E_NONE) { 11005 goto exit; 11006 } 11007 11008 /*initilization of L0.i->schedq.i->mmuq.i*/ 11009 LOG_INFO(BSL_LS_BCM_COSQ, 11010 (BSL_META_U(unit, "Profile %d cos %d L0 %d schedq %d mmuq %d cos_list %d\n"), 11011 profile_idx, cosq_idx, L0[cosq_idx], schedq[cosq_idx], mmuq[cosq_idx], cos_list[cosq_idx])); 11012 rv = soc_tomahawk3_sched_update_reinit(unit, profile_idx, L0, schedq, mmuq, cos_list, strict_priority, fc_is_uc_only); 11013 if (rv != BCM_E_NONE) { 11014 goto exit; 11015 } 11016 11017 } 11018 11019 exit: 11020 soc_mmu_cfg_scheduler_profile_free(unit, sched_profile); 11021 return rv;; 11022 } 11023 11024 #endif /* BCM_WARM_BOOT_SUPPORT */ 11025 11026 11027 #endif /* BCM_TOMAHAWK3_SUPPORT */ 11028