cosq.c (420192B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * COS Queue Management 8 * Purpose: API to set different cosq, priorities, and scheduler registers. 9 */ 10 11 #include <shared/bsl.h> 12 13 #include <sal/core/libc.h> 14 #include <soc/defs.h> 15 #if defined(BCM_TRIDENT_SUPPORT) 16 #include <bcm/types.h> 17 #include <bcm/pkt.h> 18 #include <bcm/tx.h> 19 #include <soc/drv.h> 20 #include <soc/scache.h> 21 #include <soc/profile_mem.h> 22 #include <soc/trident.h> 23 24 #include <bcm/error.h> 25 #include <bcm/cosq.h> 26 #include <bcm_int/esw/mbcm.h> 27 #include <bcm_int/esw/trident.h> 28 #include <bcm_int/esw/stack.h> 29 #include <bcm_int/esw/cosq.h> 30 31 #include <bcm_int/esw_dispatch.h> 32 33 #ifdef BCM_WARM_BOOT_SUPPORT 34 #include <bcm_int/esw/switch.h> 35 #endif /* BCM_WARM_BOOT_SUPPORT */ 36 37 #define TD_CELL_FIELD_MAX 0xffff 38 39 /* MMU cell size in bytes */ 40 #define _BCM_TD_PACKET_HEADER_BYTES 64 /* bytes */ 41 #define _BCM_TD_DEFAULT_MTU_BYTES 1536 /* bytes */ 42 #define _BCM_TD_TOTAL_CELLS 46080 /* 45k cells */ 43 #define _BCM_TD_BYTES_PER_CELL 208 /* bytes */ 44 #define _BCM_TD_BYTES_TO_CELLS(_byte_) \ 45 (((_byte_) + _BCM_TD_BYTES_PER_CELL - 1) / _BCM_TD_BYTES_PER_CELL) 46 47 #define _BCM_TD_NUM_UCAST_QUEUE_GROUP 10 48 #define _BCM_TD_NUM_MCAST_QUEUE_GROUP 5 49 #define _BCM_TD_NUM_EXT_UCAST_QUEUE_GROUP 16 50 #define _BCM_TD_NUM_SCHEDULER 9 51 #define _BCM_TD_NUM_S2_SCHEDULER 3 52 #define _BCM_TD_NUM_S3_SCHEDULER 4 53 54 #define _BCM_TD_NUM_NON_SC_QM_UCAST_QUEUE 8 55 #define _BCM_TD_NUM_NON_SC_QM_MCAST_QUEUE 4 56 57 #define _BCM_TD_S1_SCHEDULER_NUM_INPUT 7 58 #define _BCM_TD_S2_SCHEDULER_NUM_INPUT 9 59 #define _BCM_TD_S3_SCHEDULER_NUM_INPUT 2 60 #define _BCM_TD_EXT_S3_SCHEDULER_NUM_INPUT 18 61 62 #define _BCM_TD_NUM_CPU_QUEUES 48 63 #define _TD_NUM_COS NUM_COS 64 #define _BCM_TD_MAX_NUM_LLFC_EXTQ 4 /* At max, 4 EXTqs can be affected 65 by a given LLFC priority. */ 66 #define _BCM_TD_NUM_PFC_CLASS 8 /* TD supports eight PFC priorities. */ 67 68 #define WRED_MIN_PKT_SIZE 148 /* Should be greater than one cell.*/ 69 #define SOC_WRED_WR_MAX_NUM_PORTS 4 /* 1 extended and 1 non-extended port 70 from each pipeline.*/ 71 72 #define PORT_IS_VALID(_u, _p) \ 73 IS_XE_PORT(_u, _p) ? 1 : \ 74 IS_HG_PORT(_u, _p) ? 1 : 0 75 76 77 #define STG_BITS_PER_PORT 2 78 #define STG_PORTS_PER_WORD (32 / STG_BITS_PER_PORT) 79 #define STG_WORD(port) ((port) / STG_PORTS_PER_WORD) 80 #define STG_BITS_SHIFT(port) \ 81 (STG_BITS_PER_PORT * ((port) % STG_PORTS_PER_WORD)) 82 83 /* Shifts first LSB byte of the mac n times. */ 84 #define MAC_LSB_SHIFT(d, s, n) \ 85 d[5] = s[5] << n; 86 87 typedef enum { 88 _BCM_TD_COSQ_TYPE_UCAST, 89 _BCM_TD_COSQ_TYPE_MCAST, 90 _BCM_TD_COSQ_TYPE_EXT_UCAST 91 } _bcm_td_cosq_type_t; 92 93 typedef struct _bcm_td_voq_profile_s { 94 int id; 95 int hw_index; 96 int int_prio2q[16]; 97 } _bcm_td_voq_profile_t; 98 99 typedef struct _bcm_td_cosq_node_s { 100 struct _bcm_td_cosq_node_s *parent; 101 struct _bcm_td_cosq_node_s *sibling; 102 struct _bcm_td_cosq_node_s *child; 103 bcm_gport_t gport; 104 int numq; 105 int base; 106 int cosq_attached_to; 107 int hw_cosq_attached_to; 108 int level; 109 _bcm_td_voq_profile_t voq_profile; 110 } _bcm_td_cosq_node_t; 111 112 typedef struct _bcm_td_cosq_port_info_s { 113 _bcm_td_cosq_node_t ucast[_BCM_TD_NUM_UCAST_QUEUE_GROUP]; 114 _bcm_td_cosq_node_t mcast[_BCM_TD_NUM_MCAST_QUEUE_GROUP]; 115 _bcm_td_cosq_node_t ext_ucast[_BCM_TD_NUM_EXT_UCAST_QUEUE_GROUP]; 116 _bcm_td_cosq_node_t sched[_BCM_TD_NUM_SCHEDULER]; 117 } _bcm_td_cosq_port_info_t; 118 119 typedef struct _bcm_td_cosq_cpu_cosq_config_s { 120 /* All MC queues have DB and MCQE space */ 121 int enable; 122 int q_min_limit; 123 int q_shared_limit; 124 uint8 q_limit_dynamic; 125 uint8 q_limit_enable; 126 } _bcm_td_cosq_cpu_cosq_config_t; 127 128 /* Structure to store bitmaps of PFC queue. */ 129 typedef struct _bcm_td_cosq_pfc_cos_bmp_s 130 { 131 uint32 uc_bmp; /* Bitmap of unicast queue. */ 132 uint32 mc_bmp; /* Bitmap of multicast queue. */ 133 int ext_uc_count; /* Number of extended queues. */ 134 int ext_uc_qid[_BCM_TD_MAX_NUM_LLFC_EXTQ]; /* IDs of extended queues. */ 135 } _bcm_td_cosq_pfc_cos_bmp_t; 136 137 /* Global structure to store default state of port and switch. */ 138 typedef struct _wred_war_ctrl_s 139 { 140 soc_port_t port[SOC_WRED_WR_MAX_NUM_PORTS]; 141 int port_mode[SOC_WRED_WR_MAX_NUM_PORTS]; 142 int port_crc_mode[SOC_WRED_WR_MAX_NUM_PORTS]; 143 int is_ge_port[SOC_WRED_WR_MAX_NUM_PORTS]; 144 port_tab_entry_t port_entry[SOC_WRED_WR_MAX_NUM_PORTS]; 145 epc_link_bmap_entry_t epc_entry; /* EPC state. */ 146 uint32 stg_entry[SOC_MAX_MEM_WORDS]; /* STP group ports state map. */ 147 int parity_gen_en; 148 int parity_chk_en; 149 int enable[SOC_WRED_WR_MAX_NUM_PORTS]; 150 int speed[SOC_WRED_WR_MAX_NUM_PORTS]; 151 int duplex[SOC_WRED_WR_MAX_NUM_PORTS]; 152 bcm_port_abil_t advert[SOC_WRED_WR_MAX_NUM_PORTS]; 153 int autoneg[SOC_WRED_WR_MAX_NUM_PORTS]; 154 }_wred_war_ctrl_t; 155 156 _wred_war_ctrl_t war; /* Global control structure to store 157 * WRED workaround configuration. 158 */ 159 160 STATIC _bcm_td_cosq_port_info_t *_bcm_td_cosq_port_info[BCM_MAX_NUM_UNITS]; 161 STATIC soc_profile_mem_t *_bcm_td_cos_map_profile[BCM_MAX_NUM_UNITS]; 162 STATIC soc_profile_mem_t *_bcm_td_voq_cos_map_profile[BCM_MAX_NUM_UNITS]; 163 STATIC soc_profile_mem_t *_bcm_td_wred_profile[BCM_MAX_NUM_UNITS]; 164 STATIC soc_profile_mem_t *_bcm_td_sample_int_profile[BCM_MAX_NUM_UNITS]; 165 STATIC soc_profile_reg_t *_bcm_td_feedback_profile[BCM_MAX_NUM_UNITS]; 166 STATIC soc_profile_reg_t *_bcm_td_llfc_profile[BCM_MAX_NUM_UNITS]; 167 STATIC soc_profile_reg_t *_bcm_td_ext_llfc_profile[BCM_MAX_NUM_UNITS]; 168 169 STATIC _bcm_td_cosq_cpu_cosq_config_t *_bcm_td_cosq_cpu_cosq_config[BCM_MAX_NUM_UNITS][_BCM_TD_NUM_CPU_QUEUES]; 170 171 STATIC const soc_field_t _bcm_td_cpq_en_field[] = { 172 CPQ_EN0f, CPQ_EN1f, 173 CPQ_EN2f, CPQ_EN3f, 174 CPQ_EN4f, CPQ_EN5f, 175 CPQ_EN6f, CPQ_EN7f, 176 CPQ_EN8f, CPQ_EN9f 177 }; 178 STATIC const soc_field_t _bcm_td_cpq_index_field[] = { 179 CPQ_PROFILE_INDEX0f, CPQ_PROFILE_INDEX1f, 180 CPQ_PROFILE_INDEX2f, CPQ_PROFILE_INDEX3f, 181 CPQ_PROFILE_INDEX4f, CPQ_PROFILE_INDEX5f, 182 CPQ_PROFILE_INDEX6f, CPQ_PROFILE_INDEX7f, 183 CPQ_PROFILE_INDEX8f, CPQ_PROFILE_INDEX9f 184 }; 185 STATIC const soc_field_t _bcm_td_eqtb_index_field[] = { 186 EQTB_INDEX0f, EQTB_INDEX1f 187 }; 188 STATIC const soc_field_t _bcm_td_act_offset_field[] = { 189 QNTZ_ACT_OFFSET0f, QNTZ_ACT_OFFSET1f 190 }; 191 STATIC const soc_field_t _bcm_td_sitb_sel_field[] = { 192 SITB_SEL0f, SITB_SEL1f 193 }; 194 static const soc_reg_t _bcm_td_ext_uc_spid_regs[] = 195 { 196 OP_EX_PORT_CONFIG_SPID_0r, OP_EX_PORT_CONFIG_SPID_1r, 197 OP_EX_PORT_CONFIG_SPID_2r, OP_EX_PORT_CONFIG_SPID_3r, 198 OP_EX_PORT_CONFIG_SPID_4r 199 }; 200 static const soc_field_t _bcm_td_uc_spid_fields[] = { 201 COS0_SPIDf, COS1_SPIDf, COS2_SPIDf, COS3_SPIDf, 202 COS4_SPIDf, COS5_SPIDf, COS6_SPIDf, COS7_SPIDf, 203 COS8_SPIDf, COS9_SPIDf 204 }; 205 static const soc_field_t _bcm_td_ext_uc_spid_fields[] = { 206 Q0_SPIDf, Q1_SPIDf, Q2_SPIDf, Q3_SPIDf, 207 Q4_SPIDf, Q5_SPIDf, Q6_SPIDf, Q7_SPIDf, 208 Q8_SPIDf, Q9_SPIDf, Q10_SPIDf, Q11_SPIDf, 209 Q12_SPIDf, Q13_SPIDf, Q14_SPIDf, Q15_SPIDf, 210 Q16_SPIDf, Q17_SPIDf, Q18_SPIDf, Q19_SPIDf, 211 Q20_SPIDf, Q21_SPIDf, Q22_SPIDf, Q23_SPIDf, 212 Q24_SPIDf, Q25_SPIDf, Q26_SPIDf, Q27_SPIDf, 213 Q28_SPIDf, Q29_SPIDf, Q30_SPIDf, Q31_SPIDf, 214 Q32_SPIDf, Q33_SPIDf, Q34_SPIDf, Q35_SPIDf, 215 Q36_SPIDf, Q37_SPIDf, Q38_SPIDf, Q39_SPIDf, 216 Q40_SPIDf, Q41_SPIDf, Q42_SPIDf, Q43_SPIDf, 217 Q44_SPIDf, Q45_SPIDf, Q46_SPIDf, Q47_SPIDf, 218 Q48_SPIDf, Q49_SPIDf, Q50_SPIDf, Q51_SPIDf, 219 Q52_SPIDf, Q53_SPIDf, Q54_SPIDf, Q55_SPIDf, 220 Q56_SPIDf, Q57_SPIDf, Q58_SPIDf, Q59_SPIDf, 221 Q60_SPIDf, Q61_SPIDf, Q62_SPIDf, Q63_SPIDf, 222 Q64_SPIDf, Q65_SPIDf, Q66_SPIDf, Q67_SPIDf, 223 Q68_SPIDf, Q69_SPIDf, Q70_SPIDf, Q71_SPIDf, 224 Q72_SPIDf, Q73_SPIDf 225 }; 226 227 STATIC int _bcm_td_create_default_profile(int unit, bcm_port_t gport, int numq, 228 _bcm_td_voq_profile_t *profile); 229 230 STATIC int _bcm_td_voq_gport_mapping_set(int unit, bcm_port_t gport, 231 int int_prio, bcm_cos_t cos); 232 233 /* Number of COSQs configured for this device */ 234 STATIC int _bcm_td_num_cosq[SOC_MAX_NUM_DEVICES]; 235 236 extern sal_mutex_t cosq_sync_lock[SOC_MAX_NUM_DEVICES]; 237 #define TD_COSQ_LOCK(unit) do { \ 238 if (cosq_sync_lock[unit]) { \ 239 sal_mutex_take(cosq_sync_lock[unit], \ 240 sal_mutex_FOREVER); \ 241 } \ 242 } while (0) 243 #define TD_COSQ_UNLOCK(unit) do { \ 244 if (cosq_sync_lock[unit]) { \ 245 sal_mutex_give(cosq_sync_lock[unit]); \ 246 } \ 247 } while (0) 248 249 #define _BCM_TD_VOQ_QID_MIN_ID (64) 250 #define _BCM_TD_VOQ_QID_MAX_ID (127) 251 252 #define _BCM_TD_IS_VOQ_GPORT(unit, gport) \ 253 ((BCM_GPORT_IS_UCAST_QUEUE_GROUP((gport))) && \ 254 ((BCM_GPORT_UCAST_QUEUE_GROUP_QID_GET((gport)) >= _BCM_TD_NUM_UCAST_QUEUE_GROUP) && \ 255 (BCM_GPORT_UCAST_QUEUE_GROUP_QID_GET((gport)) < \ 256 (_BCM_TD_NUM_UCAST_QUEUE_GROUP + _BCM_TD_NUM_EXT_UCAST_QUEUE_GROUP)))) 257 258 259 #define _BCM_TD_NUM_COS_IN_QUEUE_GROUP(unit, gport) (4) 260 261 #define _BCM_TD_VOQ_GPORT_QUEUE_ID(unit, gport, offset) \ 262 (_BCM_TD_VOQ_QID_MIN_ID + (offset) + \ 263 ((BCM_GPORT_UCAST_QUEUE_GROUP_QID_GET((gport)) - _BCM_TD_NUM_UCAST_QUEUE_GROUP) * 16)) 264 265 #define _BCM_TD_IS_PORT_DMVOQ_CAPABLE(u, p) \ 266 (((&SOC_INFO((u)))->port_num_ext_cosq[(p)]) ? 1 : 0) 267 268 STATIC int _bcm_td_cosq_voq_init(int unit, bcm_port_t port); 269 270 STATIC int 271 _bcm_td_cosq_dynamic_thresh_enable_get(int unit, 272 bcm_gport_t gport, bcm_cos_queue_t cosq, 273 bcm_cosq_control_t type, int *arg); 274 275 /* 276 * queues on non-CPU ports: 277 * 5 multicast queue group (1 queue per group) 278 * queue 0 - 3 can connected to input 0 of S3.0 - S3.3 scheduler 279 * or input 0 - 3 of MC group scheduler 280 * queue 4 (SC/QM queue) is fixed connected to input 4 of S1 scheduler 281 * 10 unicast queue group (1 queue per group) 282 * queue 0 - 3 can connected to input 1 of S3.0 - S3.3 scheduler 283 * or input 4 - 7 of S2 scheduler 284 * queue 4 - 7 are fixed connected to input 8 - 11 of S2 scheduler 285 * queue 8 (SC queue) is fixed connected to input 5 of S1 scheduler 286 * queue 9 (QM queue) is fixed connected to input 6 of S1 scheduler 287 * 16 extended unicast queue group (up to 4 queues per group) 288 * only exist in extended queue ports 289 * queue 0 - 15 are fixed connected to input 2 - 17 of S3.0 scheduler 290 * queue 16 - 31 are fixed connected to input 2 - 17 of S3.1 scheduler 291 * queue 32 - 47 are fixed connected to input 2 - 17 of S3.2 scheduler 292 * queue 48 - 63 are fixed connected to input 2 - 17 of S3.3 scheduler 293 * schedulers on non-CPU ports: 294 * 1 S1 scheduler (7 input) 295 * 1 MC group scheduler (4 input) 296 * fixed connected to input 0 of S1 scheduler 297 * 3 S2 schedulers (12 input) 298 * scheduler 0 - 2 are fixed connected to input 1 - 3 of S1 scheduler 299 * 4 S3 schedulers (8 input for regular port, 72 input for extended port) 300 * scheduler 0 - 3 are fixed connected to input 0 - 3 of S2 scheduler 301 * 302 * Unicast queue group gport format: 303 * 31 26 25 14 13 0 304 * +-------.---+---.-------.-------.---+---.-------.-------.-------+ 305 * |0 0 1 0 0 1| sysportid (port) | qid | 306 * +-------.---+---.-------.-------.---+---.-------.-------.-------+ 307 * qid: 0 - 9 for unicast queue, 10 - 25 for extended unicast queue 308 * 309 * Multicast queue group gport format: 310 * 31 26 25 14 13 0 311 * +-------.---+---.-------.-------.---+---.-------.-------.-------+ 312 * |0 0 1 1 0 0| sysportid (port) | qid | 313 * +-------.---+---.-------.-------.---+---.-------.-------.-------+ 314 * qid: 0 - 4 315 * 316 * Scheduler gport format: 317 * 31 26 25 16 15 8 7 0 318 * +-------.---+---.-------.-------+-------.-------+-------.-------+ 319 * |0 0 1 1 0 1| scheduler id | module | port | 320 * +-------.---+---.-------.-------+-------.-------+-------.-------+ 321 * qid: 0 - 8 322 */ 323 324 #ifndef BCM_SW_STATE_DUMP_DISABLE 325 STATIC int 326 _bcm_td_cosq_port_info_dump(int unit, bcm_port_t port) 327 { 328 _bcm_td_cosq_port_info_t *port_info; 329 _bcm_td_cosq_node_t *node; 330 int index, empty; 331 332 if (!SOC_PORT_VALID(unit, port)) { 333 return BCM_E_PORT; 334 } 335 port_info = &_bcm_td_cosq_port_info[unit][port]; 336 337 empty = TRUE; 338 for (index = 0; index < _BCM_TD_NUM_SCHEDULER; index++) { 339 if (port_info->sched[index].numq > 0) { 340 empty = FALSE; 341 break; 342 } 343 } 344 if (empty) { 345 for (index = 0; index < _BCM_TD_NUM_UCAST_QUEUE_GROUP; index++) { 346 if (port_info->ucast[index].numq > 0) { 347 empty = FALSE; 348 break; 349 } 350 } 351 } 352 if (empty) { 353 for (index = 0; index < _BCM_TD_NUM_MCAST_QUEUE_GROUP; index++) { 354 if (port_info->mcast[index].numq > 0) { 355 empty = FALSE; 356 break; 357 } 358 } 359 } 360 if (empty) { 361 for (index = 0; index < _BCM_TD_NUM_EXT_UCAST_QUEUE_GROUP; index++) { 362 if (port_info->ext_ucast[index].numq > 0) { 363 empty = FALSE; 364 break; 365 } 366 } 367 } 368 369 if (empty == TRUE) { 370 return BCM_E_NOT_FOUND; 371 } 372 373 LOG_CLI((BSL_META_U(unit, 374 "=== port %d\n"), port)); 375 for (index = 0; index < _BCM_TD_NUM_UCAST_QUEUE_GROUP; index++) { 376 node = &port_info->ucast[index]; 377 LOG_CLI((BSL_META_U(unit, 378 "ucast[%d]: gport=%x numq=%d base=%d cosq_att=%d " 379 "hw_cosq_att=%d level=%d\n"), 380 index, node->gport, node->numq, node->base, 381 node->cosq_attached_to, node->hw_cosq_attached_to, 382 node->level)); 383 if (node->numq == 0) { 384 continue; 385 } 386 if (node->parent != NULL) { 387 LOG_CLI((BSL_META_U(unit, 388 " parent gport=%x\n"), node->parent->gport)); 389 } 390 if (node->sibling != NULL) { 391 LOG_CLI((BSL_META_U(unit, 392 " sibling gport=%x\n"), node->sibling->gport)); 393 } 394 if (node->child != NULL) { 395 LOG_CLI((BSL_META_U(unit, 396 " child gport=%x\n"), node->child->gport)); 397 } 398 } 399 400 for (index = 0; index < _BCM_TD_NUM_MCAST_QUEUE_GROUP; index++) { 401 node = &port_info->mcast[index]; 402 LOG_CLI((BSL_META_U(unit, 403 "mcast[%d]: gport=%x numq=%d base=%d cosq_att=%d " 404 "hw_cosq_att=%d level=%d\n"), 405 index, node->gport, node->numq, node->base, 406 node->cosq_attached_to, node->hw_cosq_attached_to, 407 node->level)); 408 if (node->numq == 0) { 409 continue; 410 } 411 if (node->parent != NULL) { 412 LOG_CLI((BSL_META_U(unit, 413 " parent gport=%x\n"), node->parent->gport)); 414 } 415 if (node->sibling != NULL) { 416 LOG_CLI((BSL_META_U(unit, 417 " sibling gport=%x\n"), node->sibling->gport)); 418 } 419 if (node->child != NULL) { 420 LOG_CLI((BSL_META_U(unit, 421 " child gport=%x\n"), node->child->gport)); 422 } 423 } 424 425 for (index = 0; index < _BCM_TD_NUM_EXT_UCAST_QUEUE_GROUP; index++) { 426 node = &port_info->ext_ucast[index]; 427 LOG_CLI((BSL_META_U(unit, 428 "ext_ucast[%d]: gport=%x numq=%d base=%d cosq_att=%d " 429 "hw_cosq_att=%d level=%d\n"), 430 index, node->gport, node->numq, node->base, 431 node->cosq_attached_to, node->hw_cosq_attached_to, 432 node->level)); 433 if (node->numq == 0) { 434 continue; 435 } 436 if (node->parent != NULL) { 437 LOG_CLI((BSL_META_U(unit, 438 " parent gport=%x\n"), node->parent->gport)); 439 } 440 if (node->sibling != NULL) { 441 LOG_CLI((BSL_META_U(unit, 442 " sibling gport=%x\n"), node->sibling->gport)); 443 } 444 if (node->child != NULL) { 445 LOG_CLI((BSL_META_U(unit, 446 " child gport=%x\n"), node->child->gport)); 447 } 448 } 449 450 for (index = 0; index < _BCM_TD_NUM_SCHEDULER; index++) { 451 node = &port_info->sched[index]; 452 LOG_CLI((BSL_META_U(unit, 453 "sched[%d]: gport=%x numq=%d base=%d cosq_att=%d " 454 "hw_cosq_att=%d level=%d\n"), 455 index, node->gport, node->numq, node->base, 456 node->cosq_attached_to, node->hw_cosq_attached_to, 457 node->level)); 458 if (node->numq == 0) { 459 continue; 460 } 461 if (node->parent != NULL) { 462 LOG_CLI((BSL_META_U(unit, 463 " parent gport=%x\n"), node->parent->gport)); 464 } 465 if (node->sibling != NULL) { 466 LOG_CLI((BSL_META_U(unit, 467 " sibling gport=%x\n"), node->sibling->gport)); 468 } 469 if (node->child != NULL) { 470 LOG_CLI((BSL_META_U(unit, 471 " child gport=%x\n"), node->child->gport)); 472 } 473 } 474 475 return BCM_E_NONE; 476 } 477 #endif /* BCM_SW_STATE_DUMP_DISABLE */ 478 479 /* 480 * Function: 481 * _bcm_td_cosq_node_get 482 * Purpose: 483 * Get internal information of queue group or scheduler type GPORT 484 * Parameters: 485 * unit - (IN) unit number 486 * gport - (IN) queue group/scheduler GPORT identifier 487 * modid - (OUT) module identifier 488 * port - (OUT) port number 489 * id - (OUT) queue group or scheduler identifier 490 * node - (OUT) node structure for the specified GPORT 491 * Returns: 492 * BCM_E_XXX 493 */ 494 STATIC int 495 _bcm_td_cosq_node_get(int unit, bcm_gport_t gport, bcm_module_t *modid, 496 bcm_port_t *port, int *id, _bcm_td_cosq_node_t **node) 497 { 498 soc_info_t *si; 499 _bcm_td_cosq_port_info_t *port_info; 500 _bcm_td_cosq_node_t *node_base; 501 bcm_module_t encap_modid, modid_out; 502 bcm_port_t encap_port, port_out; 503 uint32 encap_id; 504 int result, index; 505 506 si = &SOC_INFO(unit); 507 508 if (_bcm_td_cosq_port_info[unit] == NULL) { 509 return BCM_E_INIT; 510 } 511 512 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 513 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &modid_out)); 514 port_out = BCM_GPORT_UCAST_QUEUE_GROUP_SYSPORTID_GET(gport); 515 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 516 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &modid_out)); 517 port_out = BCM_GPORT_MCAST_QUEUE_GROUP_SYSPORTID_GET(gport); 518 } else if (BCM_GPORT_IS_SCHEDULER(gport)) { 519 encap_modid = (BCM_GPORT_SCHEDULER_GET(gport) >> 8) & 0xff; 520 BCM_IF_ERROR_RETURN 521 (_bcm_esw_modid_is_local(unit, encap_modid, &result)); 522 if (result != TRUE) { 523 return BCM_E_PORT; 524 } 525 encap_port = BCM_GPORT_SCHEDULER_GET(gport) & 0xff; 526 BCM_IF_ERROR_RETURN 527 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET, encap_modid, 528 encap_port, &modid_out, &port_out)); 529 } else { 530 return BCM_E_PORT; 531 } 532 533 if (!SOC_PORT_VALID(unit, port_out)) { 534 return BCM_E_PORT; 535 } 536 port_info = &_bcm_td_cosq_port_info[unit][port_out]; 537 538 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 539 encap_id = BCM_GPORT_UCAST_QUEUE_GROUP_QID_GET(gport); 540 index = encap_id; 541 if (index < _BCM_TD_NUM_UCAST_QUEUE_GROUP) { 542 node_base = port_info->ucast; 543 } else { 544 index -= _BCM_TD_NUM_UCAST_QUEUE_GROUP; 545 if (si->port_num_ext_cosq[port_out] == 0 || 546 index >= _BCM_TD_NUM_EXT_UCAST_QUEUE_GROUP) { 547 return BCM_E_PORT; 548 } 549 node_base = port_info->ext_ucast; 550 } 551 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 552 encap_id = BCM_GPORT_MCAST_QUEUE_GROUP_QID_GET(gport); 553 index = encap_id; 554 if (index >= _BCM_TD_NUM_MCAST_QUEUE_GROUP) { 555 return BCM_E_PORT; 556 } 557 node_base = port_info->mcast; 558 } else { /* scheduler */ 559 encap_id = (BCM_GPORT_SCHEDULER_GET(gport) >> 16) & 0x3ff; 560 index = encap_id; 561 if (index >= _BCM_TD_NUM_SCHEDULER) { 562 return BCM_E_PORT; 563 } 564 node_base = port_info->sched; 565 } 566 567 if (node_base[index].numq == 0) { 568 return BCM_E_NOT_FOUND; 569 } 570 571 if (modid != NULL) { 572 *modid = modid_out; 573 } 574 if (port != NULL) { 575 *port = port_out; 576 } 577 if (id != NULL) { 578 *id = encap_id; 579 } 580 if (node != NULL) { 581 *node = &node_base[index]; 582 } 583 584 return BCM_E_NONE; 585 } 586 587 /* 588 * Function: 589 * _bcm_td_cosq_port_resolve 590 * Purpose: 591 * Resolve following COS queue related GRPOT 592 * BCM_GPORT_TYPE_UCAST_QUEUE_GROUP 593 * BCM_GPORT_TYPE_MCAST_QUEUE_GROUP 594 * BCM_GPORT_TYPE SCHEDULER 595 * Parameters: 596 * unit - (IN) unit number 597 * gport - (IN) queue group/scheduler GPORT identifier 598 * modid - (OUT) module identifier 599 * port - (OUT) port number 600 * trunk_id - (OUT) trunk identifier 601 * id - (OUT) queue group or scheduler identifier 602 * Returns: 603 * BCM_E_XXX 604 */ 605 int 606 _bcm_td_cosq_port_resolve(int unit, bcm_gport_t gport, bcm_module_t *modid, 607 bcm_port_t *port, bcm_trunk_t *trunk_id, int *id) 608 { 609 BCM_IF_ERROR_RETURN 610 (_bcm_td_cosq_node_get(unit, gport, modid, port, id, NULL)); 611 612 if (trunk_id != NULL) { 613 *trunk_id = -1; 614 } 615 616 return BCM_E_NONE; 617 } 618 619 /* 620 * Function: 621 * _bcm_td_cosq_localport_resolve 622 * Purpose: 623 * Resolve GRPOT if it is a local port 624 * Parameters: 625 * unit - (IN) unit number 626 * gport - (IN) GPORT identifier 627 * local_port - (OUT) local port number 628 * Returns: 629 * BCM_E_XXX 630 */ 631 STATIC int 632 _bcm_td_cosq_localport_resolve(int unit, bcm_gport_t gport, 633 bcm_port_t *local_port) 634 { 635 bcm_module_t module; 636 bcm_port_t port; 637 bcm_trunk_t trunk; 638 int id, result; 639 640 if (!BCM_GPORT_IS_SET(gport)) { 641 if (!SOC_PORT_VALID(unit, gport)) { 642 return BCM_E_PORT; 643 } 644 *local_port = gport; 645 return BCM_E_NONE; 646 } else if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport) || 647 BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport) || 648 BCM_GPORT_IS_SCHEDULER(gport)) { 649 return BCM_E_PORT; 650 } 651 652 BCM_IF_ERROR_RETURN 653 (_bcm_esw_gport_resolve(unit, gport, &module, &port, &trunk, &id)); 654 655 BCM_IF_ERROR_RETURN(_bcm_esw_modid_is_local(unit, module, &result)); 656 if (result == FALSE) { 657 return BCM_E_PORT; 658 } 659 660 *local_port = port; 661 662 return BCM_E_NONE; 663 } 664 665 STATIC int 666 _bcm_td_cosq_child_node_at_input(_bcm_td_cosq_node_t *node, int cosq, 667 _bcm_td_cosq_node_t **child_node) 668 { 669 _bcm_td_cosq_node_t *cur_node; 670 671 if (NULL == node) { 672 return BCM_E_PARAM; 673 } 674 675 for (cur_node = node->child; cur_node; cur_node = cur_node->sibling) { 676 if (cur_node->cosq_attached_to == cosq) { 677 break; 678 } 679 } 680 if (!cur_node) { 681 return BCM_E_NOT_FOUND; 682 } 683 684 *child_node = cur_node; 685 686 return BCM_E_NONE; 687 } 688 689 /* 690 * Function: 691 * _bcm_td_cosq_index_resolve 692 * Purpose: 693 * Find hardware index for the given port/cosq 694 * Parameters: 695 * unit - (IN) unit number 696 * port - (IN) port number or GPORT identifier 697 * cosq - (IN) COS queue number 698 * style - (IN) index style (_BCM_TD_COSQ_INDEX_STYLE_XXX) 699 * local_port - (OUT) local port number 700 * index - (OUT) result index 701 * count - (OUT) number of index 702 * Returns: 703 * BCM_E_XXX 704 */ 705 int 706 _bcm_td_cosq_index_resolve(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 707 _bcm_td_cosq_index_style_t style, 708 bcm_port_t *local_port, int *index, int *count) 709 { 710 soc_info_t *si; 711 _bcm_td_cosq_node_t *node, *cur_node, *s3_node; 712 bcm_port_t resolved_port, mmu_port; 713 int resolved_index; 714 int id, startq, numq, is_ext_cosq; 715 716 si = &SOC_INFO(unit); 717 718 if (cosq < -1) { 719 return BCM_E_PARAM; 720 } else if (cosq == -1) { 721 startq = 0; 722 } else { 723 startq = cosq; 724 } 725 726 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port) || 727 BCM_GPORT_IS_MCAST_QUEUE_GROUP(port) || 728 BCM_GPORT_IS_SCHEDULER(port)) { 729 BCM_IF_ERROR_RETURN 730 (_bcm_td_cosq_node_get(unit, port, NULL, &resolved_port, &id, 731 &node)); 732 if (node->hw_cosq_attached_to < 0) { /* Not resolved yet */ 733 return BCM_E_NOT_FOUND; 734 } 735 numq = node->numq; 736 if (startq >= numq) { 737 return BCM_E_PARAM; 738 } 739 } else { 740 /* optionally validate port */ 741 BCM_IF_ERROR_RETURN 742 (_bcm_td_cosq_localport_resolve(unit, port, &resolved_port)); 743 if (resolved_port < 0) { 744 return BCM_E_PORT; 745 } 746 node = NULL; 747 numq = 0; 748 } 749 750 switch (style) { 751 case _BCM_TD_COSQ_INDEX_STYLE_BUCKET: 752 /* 753 * hardware index for single queue bucket control: 754 * (MAXBUCKETCONFIG_64, MAXBUCKET, 755 * MINBUCKETCONFIG_64, MINBUCKET) 756 * cpu: index 0 - 47 757 * loopback port: index 0 - 4 758 * regular port: 759 * index 0 - 9 for unicast queue 0 - queue 9 760 * index 10 - 14 for multicast queue 0 - queue 4 761 * extended queue port: 762 * index 0 - 63 for extended unicast queue 0 - queue 63 763 * index 64 - 73 for unicast queue 0 - queue 9 764 * index 74 - 78 for multicast queue 0 - queue 4 765 * hardware index for S3 schuduler bucket control: 766 * (S3_MAXBUCKETCONFIG_64, S3_MAXBUCKET, 767 * S3_MINBUCKETCONFIG_64, S3_MINBUCKET) 768 * (not for cpu port) 769 * index 0 - 3 for S3.0, S3.1, S3.2, S3.3 respectively 770 * hardware index for S2 schuduler input bucket control: 771 * (S2_MAXBUCKETCONFIG_64, S2_MAXBUCKET, 772 * S2_MINBUCKETCONFIG_64, S2_MINBUCKET) 773 * (not for cpu port) 774 * index 0 for MC group 775 * input 1 - 3 for S2.0, S2.1, S2.2 respevtively 776 * for non-gport: 777 * cpu port 778 * use cosq as hardware queue index 779 * port other than cpu: 780 * cosq 0 for the summary of unicast and multicast queue 0 781 * cosq 1 for the summary of unicast and multicast queue 1 782 * cosq 2 for the summary of unicast and multicast queue 2 783 * cosq 3 for the summary of unicast and multicast queue 3 784 * cosq 4 - 7 for unicast queue 4 - queue 7 785 * cosq 8 for unicast SC queue 786 * cosq 9 for unicast QM queue 787 * what do we want multicast SC/QM queue to be ?? 788 */ 789 if (node != NULL) { 790 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port)) { 791 if (si->port_num_ext_cosq[resolved_port] == 0) { 792 resolved_index = node->base; 793 } else { 794 if (id < _BCM_TD_NUM_UCAST_QUEUE_GROUP) { 795 /* regular unicast queue */ 796 resolved_index = 64 + node->base; 797 } else { /* extended unicast queue */ 798 resolved_index = node->base + startq * 16; 799 } 800 } 801 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(port)) { 802 if (si->port_num_ext_cosq[resolved_port] == 0) { 803 resolved_index = 10 + node->base; 804 } else { 805 resolved_index = 74 + node->base; 806 } 807 } else { /* scheduler */ 808 if (node->level == 2 || node->level == 3) { 809 numq = 1; 810 if (startq >= numq) { 811 return BCM_E_PARAM; 812 } 813 resolved_index = node->hw_cosq_attached_to; 814 } else { 815 return BCM_E_PARAM; 816 } 817 } 818 } else { /* node == NULL */ 819 if (IS_CPU_PORT(unit, resolved_port)) { 820 numq = si->port_num_cosq[resolved_port]; 821 if (startq >= numq) { 822 return BCM_E_PARAM; 823 } 824 resolved_index = startq; 825 } else { 826 numq = _BCM_TD_NUM_UCAST_QUEUE_GROUP; 827 if (startq >= numq) { 828 return BCM_E_PARAM; 829 } 830 if (startq < _BCM_TD_NUM_S3_SCHEDULER) { 831 /* use S3.0 - S3.3 for unicast and multicast queue 0 - 3 */ 832 resolved_index = startq; 833 } else { /* unicast queue 4 - 7, SC queue, QM queue */ 834 resolved_index = si->port_num_ext_cosq[resolved_port] + 835 startq; 836 } 837 } 838 } 839 break; 840 case _BCM_TD_COSQ_INDEX_STYLE_BUCKET_MODE: 841 /* 842 * hardware bit position for SHAPING_CONTROL 843 * cpu: bit 0 - 47 844 * regular port, extended queue port, and loopback port: 845 * bit 0 - 9 for unicast queue 0 - queue 9 846 * bit 10 - 14 for multicast queue 0 - queue 4 847 * bit 15 - 18 for S3.0, S3.1, S3.2, S3.3 respectively 848 * bit 19 for MC group scheduler bucket mode 849 * bit 20 - 22 for S2.0, S2.1, S2.2, respectively 850 * extended queue port: 851 * bit 23 - 86 for extended unicast queue 0 - queue 63 852 * bit 48 and up are actually in EXT1_SHAPING_CONTROL_PORTx 853 * for example bit 48 means bit 0 in EXT1_SHAPING_CONTROL_PORTx 854 * and bit 55 means bit 7 in EXT1_SHAPING_CONTROL_PORTx. 855 * for non-gport: 856 * use the same interpretation as _BCM_TD_COSQ_INDEX_STYLE_BUCKET. 857 */ 858 if (node != NULL) { 859 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port)) { 860 if (id < _BCM_TD_NUM_UCAST_QUEUE_GROUP) { 861 /* regular unicast queue */ 862 resolved_index = node->base; 863 } else { /* extended unicast queue */ 864 resolved_index = 23 + node->base + startq * 16; 865 } 866 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(port)) { 867 resolved_index = 10 + node->base; 868 } else { /* scheduler */ 869 numq = 1; 870 if (startq >= numq) { 871 return BCM_E_PARAM; 872 } 873 if (node->level == 2) { 874 resolved_index = 19 + node->hw_cosq_attached_to; 875 } else if (node->level == 3) { 876 resolved_index = 15 + node->hw_cosq_attached_to; 877 } else { 878 return BCM_E_PARAM; 879 } 880 } 881 } else { /* node == NULL */ 882 if (IS_CPU_PORT(unit, resolved_port)) { 883 numq = si->port_num_cosq[resolved_port]; 884 if (startq >= numq) { 885 return BCM_E_PARAM; 886 } 887 resolved_index = startq; 888 } else { 889 numq = _BCM_TD_NUM_UCAST_QUEUE_GROUP; 890 if (startq >= numq) { 891 return BCM_E_PARAM; 892 } 893 if (startq < _BCM_TD_NUM_S3_SCHEDULER) { 894 /* S3.0 - S3.3 for unicast queue 0 - 3 */ 895 resolved_index = 15 + startq; 896 } else { /* unicast queue 4 - 7, SC queue, QM queue */ 897 resolved_index = startq; 898 } 899 } 900 } 901 break; 902 case _BCM_TD_COSQ_INDEX_STYLE_WRED: 903 /* 904 * hardware index for regular port: 905 * (WRED_CONFIG, WRED_AVG_QSIZE) 906 * (not for cpu or loopback port) 907 * index 0 - 7 for unicast queue 0 - 7 908 * hardware index for extended queue port: 909 * (DMVOQ_WRED_CONFIG, VOQ_WRED_AVG_QSIZE) 910 * index 0 - 63 for extended unicast queue 0 - 63 911 * index 64 - 71 for unicast queue 0 - 7 912 * (WRED_CONFIG, WRED_AVG_QSIZE) 913 * index 0: summary of unicast queue 0 and extended queue 0 - 15 914 * index 1: summary of unicast queue 1 and extended queue 16 - 31 915 * index 2: summary of unicast queue 2 and extended queue 32 - 47 916 * index 3: summary of unicast queue 3 and extended queue 48 - 63 917 * these summary does not need to equal to the sum of corresponding 918 * entries in DMVOQ_WRED_CONFIG 919 * for non-gport: 920 * regular port: 921 * use cosq as hardware queue index 922 * cosq 0 - 7 for unicast queue 0 - queue 7 923 * extended queue port: 924 * cosq 0 - 7 for unicast queue 0 - queue 7 925 * cosq 8 - 71 for extended unicast queue 0 - 63 926 * instead of using hardwre queue index, adjust it to 927 * make the unicast queue has the same cosq number as regular 928 * port 929 */ 930 if (node != NULL) { 931 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port)) { 932 if (id < _BCM_TD_NUM_UCAST_QUEUE_GROUP) { 933 /* regular unicast queue */ 934 if (node->base >= _BCM_TD_NUM_NON_SC_QM_UCAST_QUEUE) { 935 /* unicast SC or QM queue */ 936 return BCM_E_PARAM; 937 } 938 if (si->port_num_ext_cosq[resolved_port] == 0) { 939 resolved_index = node->base; 940 } else { 941 resolved_index = 64 + node->base; 942 } 943 } else { /* extended unicast queue */ 944 resolved_index = node->base + startq * 16; 945 } 946 } else { /* multicast queue group or scheduler */ 947 return BCM_E_PARAM; 948 } 949 } else { /* node == NULL */ 950 if (IS_CPU_PORT(unit, resolved_port) || 951 IS_LB_PORT(unit, resolved_port)) { 952 return BCM_E_PORT; 953 } 954 /* regular ucast and extended ucast queues */ 955 numq = _BCM_TD_NUM_NON_SC_QM_UCAST_QUEUE + 956 si->port_num_ext_cosq[resolved_port]; 957 if (startq >= numq) { 958 return BCM_E_PARAM; 959 } 960 if (startq < _BCM_TD_NUM_NON_SC_QM_UCAST_QUEUE) { 961 resolved_index = si->port_num_ext_cosq[resolved_port] + startq; 962 } else { 963 resolved_index = startq - _BCM_TD_NUM_NON_SC_QM_UCAST_QUEUE; 964 } 965 } 966 break; 967 case _BCM_TD_COSQ_INDEX_STYLE_WRED_DROP_THRESH: 968 /* 969 * hardware index: 970 * (WRED_DROP_THD_UC_ENQ0, WRED_DROP_THD_UC_ENQ1, 971 * WRED_DROP_THD_UC_DEQ0, WRED_DROP_THD_UC_DEQ1) 972 * (not for cpu or loopback port) 973 * regular port: 974 * index 0 - 63 for port 1 extended unicast queue 63 - 0 975 * index 64 - 127 for port 2 extended unicast queue 63 - 0 976 * index 128 - 191 for port 3 extended unicast queue 63 - 0 977 * index 192 - 255 for port 4 extended unicast queue 63 - 0 978 * index 256 - 319 for port 34 extended unicast queue 63 - 0 979 * index 320 - 383 for port 35 extended unicast queue 63 - 0 980 * index 384 - 447 for port 36 extended unicast queue 63 - 0 981 * index 448 - 511 for port 37 extended unicast queue 63 - 0 982 * index 512 - 519 for port 64 unicast queue 0 - 7 983 * index 520 - 775 for port 1 - 32 unicast queue 0 - 7 984 * index 776 - 783 for port 65 unicast queue 0 - 7 985 * index 784 - 1023 for port 34 - 63 unicast queue 0 - 7 986 * for non-gport: 987 * regular port: 988 * use cosq as hardware queue index 989 * cosq 0 - 7 for unicast queue 0 - queue 7 990 * extended queue port: 991 * cosq 0 - 7 for unicast queue 0 - queue 7 992 * cosq 8 - 71 for extended unicast queue 0 - 63 993 */ 994 is_ext_cosq = FALSE; 995 if (node != NULL) { 996 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port)) { 997 if (id < _BCM_TD_NUM_UCAST_QUEUE_GROUP) { 998 /* regular unicast queue */ 999 if (node->base >= _BCM_TD_NUM_NON_SC_QM_UCAST_QUEUE) { 1000 /* unicast SC or QM queue */ 1001 return BCM_E_PARAM; 1002 } 1003 resolved_index = node->base; 1004 } else { /* extended unicast queue */ 1005 resolved_index = 63 - node->base + startq * 16; 1006 is_ext_cosq = TRUE; 1007 } 1008 } else { /* multicast queue group or scheduler */ 1009 return BCM_E_PARAM; 1010 } 1011 } else { /* node == NULL */ 1012 if (IS_CPU_PORT(unit, resolved_port) || 1013 IS_LB_PORT(unit, resolved_port)) { 1014 return BCM_E_PORT; 1015 } 1016 /* regular ucast and extended ucast queues */ 1017 numq = _BCM_TD_NUM_NON_SC_QM_UCAST_QUEUE + 1018 si->port_num_ext_cosq[resolved_port]; 1019 if (startq >= numq) { 1020 return BCM_E_PARAM; 1021 } 1022 if (startq < _BCM_TD_NUM_NON_SC_QM_UCAST_QUEUE) { 1023 resolved_index = startq; 1024 } else { 1025 resolved_index = 1026 63 - (startq - _BCM_TD_NUM_NON_SC_QM_UCAST_QUEUE); 1027 is_ext_cosq = TRUE; 1028 } 1029 } 1030 /* Add port base offset */ 1031 mmu_port = si->port_p2m_mapping[si->port_l2p_mapping[resolved_port]]; 1032 if (is_ext_cosq) { 1033 if (mmu_port < 33) { 1034 resolved_index += (mmu_port - 1) * 1035 si->port_num_ext_cosq[resolved_port]; 1036 } else { 1037 resolved_index += 256 + (mmu_port - 34) * 1038 si->port_num_ext_cosq[resolved_port]; 1039 } 1040 } else { 1041 if (mmu_port < 64) { 1042 resolved_index += 1043 512 + mmu_port * _BCM_TD_NUM_NON_SC_QM_UCAST_QUEUE; 1044 } else if (mmu_port == 64) { 1045 resolved_index += 512; 1046 } else { 1047 resolved_index += 776; 1048 } 1049 } 1050 break; 1051 case _BCM_TD_COSQ_INDEX_STYLE_SCHEDULER: 1052 /* 1053 * hardware index for (S1) COSWEIGHTS: 1054 * cpu port 1055 * index 0 - 47 are for queue 0 - 47 1056 * regular port, extended queue port, and loopback port: 1057 * index 0 is for multicast group scheduler 1058 * index 1 - 3 are for S2.1, S2.2, S2.3 respectively 1059 * index 4 is for multicast SC and QM queue 1060 * index 5 is for unicast SC queue 1061 * index 6 is for unicast QM queue 1062 * hardware index for S2_COSWEIGHTS: 1063 * (not for cpu port) 1064 * index 0 - 3 are for S3.0, S3.1, S3.2, S3.3 respectively 1065 * index 4 - 11 are for unicast queue 0 - 7 1066 * hardware bit position for S2_COSMASK, S2_MINSPCONFIG: 1067 * (not for cpu port) 1068 * bit 0 - 3 are for S3.0, S3.1, S3.2, S3.3 respectively 1069 * bit 4 - 11 are for unicast queue 0 - 7 1070 * hardware index for S3_COSWEIGHTS: 1071 * (not for cpu port) 1072 * regular port: 1073 * index 0, 2, 4, 6 are for multicast queue 0, 1, 2, 3 1074 * respectively 1075 * index 1, 3, 5, 7 are for unicast queue 0, 1, 2, 3 1076 * respectively 1077 * extended queue port: 1078 * index 0, 18, 36, 54 are for multicast queue 0, 1, 2, 3 1079 * respectively 1080 * index 1, 19, 37, 55 are for unicast queue 0, 1, 2, 3 1081 * respectively 1082 * index 2 - 17 are for extended unicast queue 0 - 15 1083 * index 20 - 35 are for extended unicast queue 16 - 31 1084 * index 38 - 53 are for extended unicast queue 32 - 47 1085 * index 56 - 71 are for extended unicast queue 48 - 63 1086 * hardware bit position for S3_COSMASK, S3_MINSPCONFIG: 1087 * (not for cpu port) 1088 * there are 4 entries in each register 1089 * entry 0 is for input to S3.0 1090 * entry 1 is for input to S3.1 1091 * entry 2 is for input to S3.2 1092 * entry 3 is for input to S3.3 1093 * regular port and extended queue port: 1094 * bit 0 of entry 0 is for multicast queue 0 1095 * bit 0 of entry 1 is for multicast queue 1 1096 * bit 0 of entry 2 is for multicast queue 2 1097 * bit 0 of entry 3 is for multicast queue 3 1098 * bit 1 of entry 0 is for unicast queue 0 1099 * bit 1 of entry 1 is for unicast queue 1 1100 * bit 1 of entry 2 is for unicast queue 2 1101 * bit 1 of entry 3 is for unicast queue 3 1102 * extended queue port: 1103 * bit 2 - 17 of entry 0 are for extended unicast queue 0 - 15 1104 * bit 2 - 17 of entry 1 are for extended unicast queue 16 - 31 1105 * bit 2 - 17 of entry 2 are for extended unicast queue 32 - 47 1106 * bit 2 - 17 of entry 3 are for extended unicast queue 48 - 63 1107 * hardware bit position for S3_COSMASK_MC, S3_MINSPCONFIG_MC: 1108 * bit 0 - 3 for multicast queue 0 - 3 1109 */ 1110 if (node != NULL) { 1111 if (BCM_GPORT_IS_SCHEDULER(port)) { 1112 for (cur_node = node->child; cur_node != NULL; 1113 cur_node = cur_node->sibling) { 1114 if (cur_node->cosq_attached_to == startq) { 1115 break; 1116 } 1117 } 1118 if (cur_node == NULL) { 1119 if (node->level == 3 && 1120 si->port_num_ext_cosq[resolved_port] != 0) { 1121 /* search to see if it matches the extended unicast 1122 * queue index from the corresponding S3.0 node */ 1123 for (s3_node = node->parent->child; s3_node != NULL; 1124 s3_node = s3_node->sibling) { 1125 if (s3_node->hw_cosq_attached_to == 0) { /* S3.0 */ 1126 break; 1127 } 1128 } 1129 if (s3_node != NULL) { 1130 for (cur_node = s3_node->child; cur_node != NULL; 1131 cur_node = cur_node->sibling) { 1132 if (cur_node->cosq_attached_to == startq) { 1133 break; 1134 } 1135 } 1136 } 1137 } 1138 } 1139 if (cur_node == NULL) { 1140 /* Nothing is attached to the specified cosq */ 1141 resolved_index = -1; 1142 } else if (node->level == 3) { /* S3 scheduler */ 1143 resolved_index = node->hw_cosq_attached_to * 1144 (si->port_num_ext_cosq[resolved_port] ? 18 : 2) + 1145 cur_node->hw_cosq_attached_to; 1146 } else if (node->level == 2 && 1147 node->hw_cosq_attached_to == 0) { 1148 /* MC group scheduler */ 1149 resolved_index = cur_node->hw_cosq_attached_to * 1150 (si->port_num_ext_cosq[resolved_port] ? 18 : 2); 1151 } else { /* S1 or S2 scheduler */ 1152 resolved_index = cur_node->hw_cosq_attached_to; 1153 } 1154 } else { /* unicast queue group or multicast queue group */ 1155 return BCM_E_PARAM; 1156 } 1157 } else { /* node == NULL */ 1158 if (IS_CPU_PORT(unit, resolved_port)) { 1159 numq = si->num_cpu_cosq; 1160 if (startq >= numq) { 1161 return BCM_E_PARAM; 1162 } 1163 resolved_index = startq; 1164 } else { /* S2.0 scheduler */ 1165 numq = _BCM_TD_NUM_NON_SC_QM_UCAST_QUEUE; 1166 if (startq >= numq) { 1167 return BCM_E_PARAM; 1168 } 1169 /* 1170 * cosq 0 - 3 (via S3.0 - S3.3) map to index 0 - 3 1171 * cosq 4 - 7 map to index 8 - 11 1172 */ 1173 resolved_index = startq >= 4 ? startq + 4 : startq; 1174 } 1175 } 1176 break; 1177 case _BCM_TD_COSQ_INDEX_STYLE_PERQ_XMT: 1178 /* 1179 * software assigned index for cpu port: 1180 * index 0 - 47 1181 * software assigned index for loopback port: 1182 * index 0 - 8 1183 * software assigned index for regular port: 1184 * index 0 - 9 for unicast queue 0 - 9 1185 * index 10 - 14 for multicast queue 0 - 4 1186 * software assigned index for extended queue port: 1187 * index 0 - 9 for unicast queue 0 - 9 1188 * index 10 - 14 for multicast queue 0 - 4 1189 * index 15 - 78 for extended unicast queue 0 - 63 1190 */ 1191 if (node != NULL) { 1192 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port)) { 1193 if (id < _BCM_TD_NUM_UCAST_QUEUE_GROUP) { 1194 /* regular unicast queue */ 1195 resolved_index = node->base; 1196 } else { /* extended unicast queue */ 1197 resolved_index = si->port_num_uc_cosq[resolved_port] + 1198 si->port_num_cosq[resolved_port] + 1199 node->base + startq * 16; 1200 } 1201 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(port)) { 1202 /* multicast queue */ 1203 resolved_index = si->port_num_uc_cosq[resolved_port] + 1204 node->base; 1205 } else { /* scheduler */ 1206 return BCM_E_PARAM; 1207 } 1208 } else { /* node == NULL */ 1209 numq = si->port_num_uc_cosq[resolved_port] + 1210 si->port_num_cosq[resolved_port] + 1211 si->port_num_ext_cosq[resolved_port]; 1212 if (startq >= numq) { 1213 return BCM_E_PARAM; 1214 } 1215 resolved_index = startq; 1216 } 1217 break; 1218 case _BCM_TD_COSQ_INDEX_STYLE_UCAST_DROP: 1219 if (node != NULL) { 1220 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port)) { 1221 if (id >= _BCM_TD_NUM_UCAST_QUEUE_GROUP) { 1222 /* extended unicast queue */ 1223 return BCM_E_PARAM; 1224 } 1225 if (si->port_num_ext_cosq[resolved_port] == 0) { 1226 resolved_index = node->base; 1227 } else { 1228 resolved_index = 64 + node->base; 1229 } 1230 } else { /* multicast queue group or scheduler */ 1231 return BCM_E_PARAM; 1232 } 1233 } else { /* node == NULL */ 1234 numq = si->port_num_uc_cosq[resolved_port]; 1235 if (startq >= numq) { 1236 return BCM_E_PARAM; 1237 } 1238 if (si->port_num_ext_cosq[resolved_port] == 0) { 1239 resolved_index = startq; 1240 } else { 1241 resolved_index = 64 + startq; 1242 } 1243 } 1244 break; 1245 case _BCM_TD_COSQ_INDEX_STYLE_UCAST_QUEUE: 1246 if (node != NULL) { 1247 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port)) { 1248 if (id >= _BCM_TD_NUM_UCAST_QUEUE_GROUP) { 1249 /* extended unicast queue */ 1250 return BCM_E_PARAM; 1251 } 1252 resolved_index = node->base; 1253 } else { /* multicast queue group or scheduler */ 1254 return BCM_E_PARAM; 1255 } 1256 } else { /* node == NULL */ 1257 numq = si->port_num_uc_cosq[resolved_port]; 1258 if (startq >= numq) { 1259 return BCM_E_PARAM; 1260 } 1261 resolved_index = startq; 1262 } 1263 break; 1264 case _BCM_TD_COSQ_INDEX_STYLE_MCAST_QUEUE: 1265 if (node != NULL) { 1266 if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(port)) { 1267 resolved_index = node->base; 1268 } else { /* unicast queue group or scheduler */ 1269 return BCM_E_PARAM; 1270 } 1271 } else { /* node == NULL */ 1272 numq = si->port_num_cosq[resolved_port]; 1273 if (startq >= numq) { 1274 return BCM_E_PARAM; 1275 } 1276 resolved_index = startq; 1277 } 1278 break; 1279 case _BCM_TD_COSQ_INDEX_STYLE_EXT_UCAST_QUEUE: 1280 if (node != NULL) { 1281 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port)) { 1282 if (id < _BCM_TD_NUM_UCAST_QUEUE_GROUP) { 1283 /* regular unicast queue */ 1284 return BCM_E_PARAM; 1285 } 1286 resolved_index = node->base + startq * 16; 1287 } else { /* multicast queue group or scheduler */ 1288 return BCM_E_PARAM; 1289 } 1290 } else { /* node == NULL */ 1291 numq = si->port_num_ext_cosq[resolved_port]; 1292 if (startq >= numq) { 1293 return BCM_E_PARAM; 1294 } 1295 resolved_index = startq; 1296 } 1297 break; 1298 case _BCM_TD_COSQ_INDEX_STYLE_EGR_POOL: 1299 if (node != NULL) { 1300 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port)) { 1301 if (id < _BCM_TD_NUM_UCAST_QUEUE_GROUP) { 1302 /* regular unicast queue */ 1303 resolved_index = node->base; 1304 } else { /* extended unicast queue */ 1305 resolved_index = node->base + startq * 16; 1306 } 1307 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(port)) { 1308 resolved_index = node->base; 1309 } else { /* scheduler */ 1310 return BCM_E_PARAM; 1311 } 1312 } else { /* node == NULL */ 1313 numq = si->port_num_cosq[resolved_port]; 1314 if (startq >= numq) { 1315 return BCM_E_PARAM; 1316 } 1317 resolved_index = startq; 1318 } 1319 break; 1320 1321 case _BCM_TD_COSQ_INDEX_STYLE_UC_EGR_POOL: 1322 numq = si->port_num_uc_cosq[resolved_port]; 1323 if (startq >= numq) { 1324 return BCM_E_PARAM; 1325 } 1326 resolved_index = startq; 1327 break; 1328 1329 default: 1330 return BCM_E_INTERNAL; 1331 } 1332 1333 if (index != NULL) { 1334 if (resolved_index == -1) { 1335 return BCM_E_NOT_FOUND; 1336 } 1337 *index = resolved_index; 1338 } 1339 if (local_port != NULL) { 1340 *local_port = resolved_port; 1341 } 1342 if (count != NULL) { 1343 *count = cosq == -1 ? numq : 1; 1344 } 1345 1346 return BCM_E_NONE; 1347 } 1348 1349 /* 1350 * Function: 1351 * _bcm_td_cosq_node_resolve 1352 * Purpose: 1353 * Resolve queue number in the specified scheduler tree and its subtree 1354 * Parameters: 1355 * unit - (IN) unit number 1356 * port - (IN) port number 1357 * node - (IN) node structure for the specified scheduler node 1358 * cosq - (IN) COS queue to attach to 1359 * Returns: 1360 * BCM_E_XXX 1361 */ 1362 STATIC int 1363 _bcm_td_cosq_node_resolve(int unit, bcm_port_t port, _bcm_td_cosq_node_t *node, 1364 bcm_cos_queue_t cosq) 1365 { 1366 soc_info_t *si; 1367 _bcm_td_cosq_node_t *s1_node, *s2_node, *q_node, *cur_node; 1368 uint32 map, s1_map, s2_map, mcg_map, s3_mc_map, s3_uc_map, s3_ext_uc_map; 1369 int base, i; 1370 1371 if (node->parent == NULL) { 1372 /* Not attached, should never happen */ 1373 return BCM_E_NOT_FOUND; 1374 } 1375 1376 si = &SOC_INFO(unit); 1377 1378 /* find the current cosq_attached_to usage */ 1379 map = 0; 1380 for (cur_node = node->parent->child; cur_node != NULL; 1381 cur_node = cur_node->sibling) { 1382 if (cur_node->cosq_attached_to >= 0) { 1383 map |= 1 << cur_node->cosq_attached_to; 1384 } 1385 } 1386 1387 if (cosq < 0) { 1388 for (i = 0; i < node->parent->numq; i++) { 1389 if ((map & (1 << i)) == 0) { 1390 node->cosq_attached_to = i; 1391 break; 1392 } 1393 } 1394 if (i == node->parent->numq) { 1395 return BCM_E_PARAM; 1396 } 1397 } else { 1398 if (map & (1 << cosq)) { 1399 return BCM_E_EXISTS; 1400 } 1401 node->cosq_attached_to = cosq; 1402 } 1403 node->hw_cosq_attached_to = -1; 1404 1405 /* find the current S3 to S2 mapping */ 1406 s3_mc_map = 0; 1407 s3_uc_map = 0; 1408 s3_ext_uc_map = 0; 1409 s2_map = 0; 1410 mcg_map = 0; 1411 s1_map = 0; 1412 for (s1_node = node->parent; s1_node->parent != NULL; 1413 s1_node = s1_node->parent); 1414 for (s2_node = s1_node->child; s2_node != NULL; 1415 s2_node = s2_node->sibling) { 1416 if (s2_node->hw_cosq_attached_to < 0) { 1417 /* S2/MC group node may not be resolved yet */ 1418 continue; 1419 } 1420 s1_map |= 1 << s2_node->hw_cosq_attached_to; 1421 if (s2_node->hw_cosq_attached_to == 0) { /* MC group node */ 1422 for (q_node = s2_node->child; q_node != NULL; 1423 q_node = q_node->sibling) { 1424 mcg_map |= 1 << q_node->hw_cosq_attached_to; 1425 } 1426 } else if (s2_node->hw_cosq_attached_to < 4) { 1427 /* S2 node can be mapped to input 1, 2, or 3 of S1 node */ 1428 for (cur_node = s2_node->child; cur_node != NULL; 1429 cur_node = cur_node->sibling) { 1430 s2_map |= 1 << cur_node->hw_cosq_attached_to; 1431 if (cur_node->hw_cosq_attached_to < 4) { 1432 /* S3 node can be mapped to input 0, 1, 2, or 3 of S2 1433 * node */ 1434 for (q_node = cur_node->child; q_node != NULL; 1435 q_node = q_node->sibling) { 1436 if (q_node->hw_cosq_attached_to < 0) { 1437 continue; 1438 } else if (q_node->hw_cosq_attached_to == 0) { 1439 /* multicast queue is always mapped to input 0 of 1440 * S3 node */ 1441 s3_mc_map |= 1 << cur_node->hw_cosq_attached_to; 1442 } else if (q_node->hw_cosq_attached_to == 1) { 1443 /* unicast queue is always mapped to input 1 of 1444 * S3 node */ 1445 s3_uc_map |= 1 << cur_node->hw_cosq_attached_to; 1446 } else { 1447 /* extended unicast queue can be mapped to input 2 1448 * to 17 of S3 node */ 1449 s3_ext_uc_map |= 1450 1 << (q_node->hw_cosq_attached_to - 2); 1451 } 1452 } 1453 } 1454 } 1455 } 1456 } 1457 1458 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(node->gport)) { 1459 if (BCM_GPORT_UCAST_QUEUE_GROUP_QID_GET(node->gport) < 1460 _BCM_TD_NUM_UCAST_QUEUE_GROUP) { 1461 /* regular ucast queue */ 1462 if (node->parent->level == 1) { 1463 if ((s1_map & 0x60) == 0x60) { 1464 /* both SC queue and QM queue have been assigned */ 1465 return BCM_E_FAIL; 1466 } 1467 } else if (node->parent->level == 2) { 1468 if (node->parent->hw_cosq_attached_to == 0) { 1469 /* ucast queue can not attach to MC group */ 1470 return BCM_E_FAIL; 1471 } 1472 if (((s2_map & 0xf00) == 0xf00) && s3_uc_map != 0) { 1473 /* ucast queue 4-7 have already been assigned, 1474 * but one or more of ucast queue 0-3 has attached to S3 */ 1475 return BCM_E_FAIL; 1476 } 1477 } else if (node->parent->level == 3) { 1478 if ((s2_map & 0x0f0) != 0) { 1479 /* One or more of ucast queue 0-3 has attached to S2 */ 1480 return BCM_E_FAIL; 1481 } 1482 } else { 1483 return BCM_E_FAIL; 1484 } 1485 } else { 1486 /* extended ucast queue */ 1487 if (node->parent->level != 3) { 1488 return BCM_E_FAIL; 1489 } 1490 } 1491 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(node->gport)) { 1492 if (node->parent->level == 1) { 1493 if ((s1_map & 0x10) == 0x10) { 1494 /* multicast SC/QM queue has been assigned */ 1495 return BCM_E_FAIL; 1496 } 1497 } else if (node->parent->level == 2) { 1498 if (node->parent->hw_cosq_attached_to >= 1 && 1499 node->parent->hw_cosq_attached_to <= 3) { 1500 /* mcast queue can not attach to S2 */ 1501 return BCM_E_FAIL; 1502 } 1503 if (s3_mc_map != 0) { 1504 /* Some mcast queue has attached to S3 */ 1505 return BCM_E_FAIL; 1506 } 1507 } else if (node->parent->level == 3) { 1508 if (mcg_map != 0) { 1509 /* Some mcast queue has attached to MC group */ 1510 return BCM_E_FAIL; 1511 } 1512 } else { 1513 return BCM_E_FAIL; 1514 } 1515 } else if (BCM_GPORT_IS_SCHEDULER(node->gport)) { 1516 if (node->parent->level == 1) { 1517 if ((s1_map & 0x00f) == 0x00f) { 1518 /* There are only 3 S2 schedulers and 1 MC group scheduler */ 1519 return BCM_E_FAIL; 1520 } 1521 if (node->numq > _BCM_TD_S2_SCHEDULER_NUM_INPUT) { 1522 /* hardware allows up to 9 input */ 1523 return BCM_E_FAIL; 1524 } 1525 } else if (node->parent->level == 2) { 1526 if ((s2_map & 0x00f) == 0x00f) { 1527 /* There are only 4 S3 schedulers */ 1528 return BCM_E_FAIL; 1529 } 1530 if (si->port_num_ext_cosq[port] == 0) { /* regular port */ 1531 if (node->numq > _BCM_TD_S3_SCHEDULER_NUM_INPUT) { 1532 /* possible input: 1 UC, 1 MC */ 1533 return BCM_E_FAIL; 1534 } 1535 } else { /* extended queue port */ 1536 if (node->numq > _BCM_TD_EXT_S3_SCHEDULER_NUM_INPUT) { 1537 /* possible input: 1 UC, 1 MC, 16 EXT UC */ 1538 return BCM_E_FAIL; 1539 } 1540 } 1541 } else { 1542 return BCM_E_FAIL; 1543 } 1544 } else { 1545 return BCM_E_INTERNAL; 1546 } 1547 1548 /* Resolve S2/MC group node if needed */ 1549 if (node->parent->level == 2 && node->parent->hw_cosq_attached_to < 0) { 1550 s2_node = node->parent; 1551 if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(node->gport)) { 1552 /* MC group node is always mapped to input 0 of S1 node */ 1553 s2_node->hw_cosq_attached_to = 0; 1554 s2_node->base = 0; 1555 } else { 1556 /* S2 node can be mapped to input 1, 2, or 3 of S1 node */ 1557 for (i = 1; i < 4; i++) { 1558 if ((s1_map & (1 << i)) == 0) { 1559 s2_node->hw_cosq_attached_to = i; 1560 s2_node->base = 0; 1561 break; 1562 } 1563 } 1564 if (s2_node->hw_cosq_attached_to < 0) { 1565 return BCM_E_FAIL; 1566 } 1567 } 1568 } 1569 1570 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(node->gport)) { 1571 if (BCM_GPORT_UCAST_QUEUE_GROUP_QID_GET(node->gport) < 1572 _BCM_TD_NUM_UCAST_QUEUE_GROUP) { 1573 /* regular unicast queue */ 1574 if (node->parent->level == 1) { 1575 if (!(s1_map & 0x20)) { /* unicast SC queue */ 1576 node->hw_cosq_attached_to = 5; 1577 node->base = 8; 1578 } else { /* unicast QM queue */ 1579 node->hw_cosq_attached_to = 6; 1580 node->base = 9; 1581 } 1582 } else if (node->parent->level == 2) { 1583 /* If regular unicast queue is attached to S2 scheduler, 1584 * queue 0 - 3 can be mapped to input 4 - 7 of S2 node, 1585 * queue 4 - 7 are fixed mapped to input 8 - 11 of S2 node */ 1586 base = (s2_map & 0xf00) == 0xf00 ? 4 : 8; 1587 for (i = 0; i < 4; i++) { 1588 if ((s2_map & (1 << (base + i))) == 0) { 1589 node->hw_cosq_attached_to = base + i; 1590 node->base = node->hw_cosq_attached_to - 4; 1591 break; 1592 } 1593 } 1594 } else if (node->parent->level == 3) { 1595 /* If regular unicast queue is attached to S3 scheduler, 1596 * queue 0 - 3 are fixed mapped to input 1 of S3 node 0 - 3, 1597 * S3 node 0 - 3 are mapped to input 0 - 3 of each S2 node */ 1598 node->hw_cosq_attached_to = 1; 1599 node->base = node->parent->hw_cosq_attached_to; 1600 } else { 1601 return BCM_E_FAIL; 1602 } 1603 } else { /* extended unicast queue */ 1604 if (node->parent->level == 3) { 1605 /* queue 0 - 15 are fixed mapped to input 2 - 17 of S3 node 0, 1606 * queue 16 - 31 are fixed mapped to input 2 - 17 of S3 node 1, 1607 * queue 32 - 47 are fixed mapped to input 2 - 17 of S3 node 2, 1608 * queue 48 - 63 are fixed mapped to input 2 - 17 of S3 node 3, 1609 * S3 node 0 - 3 are mapped to input 0 - 3 of each S2 node */ 1610 for (i = 0; i < _BCM_TD_NUM_EXT_UCAST_QUEUE_GROUP; i++) { 1611 if ((s3_ext_uc_map & (1 << i)) == 0) { 1612 node->hw_cosq_attached_to = 2 + i; 1613 node->base = i; 1614 s3_ext_uc_map |= 1 << i; 1615 break; 1616 } 1617 } 1618 } 1619 } 1620 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(node->gport)) { 1621 if (node->parent->level == 1) { /* multicast SC/QM queue */ 1622 node->hw_cosq_attached_to = 4; 1623 node->base = 4; 1624 } else if (node->parent->level == 2) { 1625 /* If multicast queue is attached to MC group scheduler, 1626 * queue 0 - 3 are mapped to input 0 - 3 of MC group node */ 1627 for (i = 0; i < _BCM_TD_NUM_MCAST_QUEUE_GROUP; i++) { 1628 if ((mcg_map & (1 << i)) == 0) { 1629 node->hw_cosq_attached_to = i; 1630 node->base = i; 1631 break; 1632 } 1633 } 1634 } else if (node->parent->level == 3) { 1635 /* If multicast queue is attached to S3 scheduler, 1636 * queue 0 - 3 are fixed mapped to input 0 of S3 node 0 - 3, 1637 * S3 node 0 - 3 are mapped to input 0 - 3 of each S2 node */ 1638 node->hw_cosq_attached_to = 0; 1639 node->base = node->parent->hw_cosq_attached_to; 1640 } 1641 } else if (BCM_GPORT_IS_SCHEDULER(node->gport)) { 1642 if (node->parent->level == 1) { 1643 /* We can not foresee if this node is S2.x or MC group yet */ 1644 } else if (node->parent->level == 2 ) { 1645 for (i = 0; i < _BCM_TD_NUM_S3_SCHEDULER; i++) { 1646 /* S3 node can be mapped to input 0, 1, 2, or 3 of S2 node */ 1647 if ((s2_map & (1 << i)) == 0) { 1648 node->hw_cosq_attached_to = i; 1649 node->base = 0; 1650 break; 1651 } 1652 } 1653 } 1654 node->level = node->parent->level + 1; 1655 } 1656 1657 return BCM_E_NONE; 1658 } 1659 1660 STATIC int 1661 _bcm_td_cosq_sched_node_set(int unit, bcm_port_t port) 1662 { 1663 uint64 rval64[3]; 1664 uint32 rval; 1665 int uc_to_s2, use_mc_group, index; 1666 _bcm_td_cosq_port_info_t *port_info; 1667 _bcm_td_cosq_node_t *s1_node, *s2_node, *cur_node; 1668 int i; 1669 static const soc_field_t fields[] = { 1670 S3_GROUP_NO_I0f, S3_GROUP_NO_I1f, S3_GROUP_NO_I2f, S3_GROUP_NO_I3f, 1671 S3_GROUP_NO_I4f, S3_GROUP_NO_I5f, S3_GROUP_NO_I6f, S3_GROUP_NO_I7f, 1672 S3_GROUP_NO_I8f 1673 }; 1674 1675 COMPILER_64_ZERO(rval64[0]); 1676 for (index = 0; index < 9; index++) { 1677 soc_reg64_field32_set(unit, S2_S3_ROUTINGr, &rval64[0], fields[index], 1678 0x1f); 1679 } 1680 rval64[1] = rval64[0]; 1681 rval64[2] = rval64[0]; 1682 1683 port_info = &_bcm_td_cosq_port_info[unit][port]; 1684 s1_node = NULL; 1685 for (i = 0; i < _BCM_TD_NUM_SCHEDULER; i++) { 1686 if (port_info->sched[i].level == 1) { 1687 s1_node = &port_info->sched[i]; 1688 break; 1689 } 1690 } 1691 if (s1_node != NULL) { 1692 use_mc_group = 0; 1693 uc_to_s2 = 0; 1694 for (s2_node = s1_node->child; s2_node != NULL; 1695 s2_node = s2_node->sibling) { 1696 if (s2_node->hw_cosq_attached_to < 0) { 1697 continue; 1698 } else if (s2_node->hw_cosq_attached_to == 0) { /* MC group */ 1699 if (s2_node->child != NULL) { 1700 use_mc_group = 1; 1701 } 1702 } else if (s2_node->hw_cosq_attached_to < 4) { /* S2 */ 1703 index = s2_node->hw_cosq_attached_to - 1; 1704 for (cur_node = s2_node->child; cur_node != NULL; 1705 cur_node = cur_node->sibling) { 1706 soc_reg64_field32_set(unit, S2_S3_ROUTINGr, &rval64[index], 1707 fields[cur_node->cosq_attached_to], 1708 cur_node->hw_cosq_attached_to); 1709 if (cur_node->hw_cosq_attached_to >= 4 && 1710 cur_node->hw_cosq_attached_to < 8) { 1711 /* at least one of unicast queue 0 - 3 is directly 1712 * attached to S2 */ 1713 uc_to_s2 = 1; 1714 } 1715 } 1716 } 1717 } 1718 1719 BCM_IF_ERROR_RETURN(READ_S3_CONFIGr(unit, port, &rval)); 1720 soc_reg_field_set(unit, S3_CONFIGr, &rval, ROUTE_UC_TO_S2f, uc_to_s2); 1721 BCM_IF_ERROR_RETURN(WRITE_S3_CONFIGr(unit, port, rval)); 1722 1723 BCM_IF_ERROR_RETURN(READ_S3_CONFIG_MCr(unit, port, &rval)); 1724 soc_reg_field_set(unit, S3_CONFIG_MCr, &rval, USE_MC_GROUPf, 1725 use_mc_group); 1726 BCM_IF_ERROR_RETURN(WRITE_S3_CONFIG_MCr(unit, port, rval)); 1727 } else { 1728 /* make it act like a non-ETS style scheduler 1729 * unicast queue 0 and multicast queue 0 connect to S3.0 1730 * unicast queue 1 and multicast queue 1 connect to S3.1 1731 * unicast queue 2 and multicast queue 2 connect to S3.2 1732 * unicast queue 3 and multicast queue 3 connect to S3.3 1733 * S3.0 - S3.3 and unicast queue 4 - 7 connect to S2.0 1734 * S2.1, S2.2, MC group are not used 1735 */ 1736 /* S3.0 - S3.3 to S2.0 input 0 - 3 (S3 group number 0 - 3)*/ 1737 for (i = 0; i < _BCM_TD_NUM_S3_SCHEDULER; i++) { 1738 soc_reg64_field32_set(unit, S2_S3_ROUTINGr, &rval64[0], fields[i], 1739 i); 1740 } 1741 /* unicast queues 4 - 7 to S2.0 input 4 - 7 (S3 group number 8 - 11) */ 1742 for (i = _BCM_TD_NUM_S3_SCHEDULER; 1743 i < _BCM_TD_NUM_NON_SC_QM_UCAST_QUEUE; i++) { 1744 soc_reg64_field32_set(unit, S2_S3_ROUTINGr, &rval64[0], fields[i], 1745 i + 4); 1746 } 1747 1748 rval = 0; 1749 soc_reg_field_set(unit, S3_CONFIGr, &rval, SCHEDULING_SELECTf, 0x55); 1750 BCM_IF_ERROR_RETURN(WRITE_S3_CONFIGr(unit, port, rval)); 1751 1752 BCM_IF_ERROR_RETURN(WRITE_S3_CONFIG_MCr(unit, port, 0)); 1753 1754 rval = 0; 1755 soc_reg_field_set(unit, S2_CONFIGr, &rval, SCHEDULING_SELECTf, 0x15); 1756 BCM_IF_ERROR_RETURN(WRITE_S2_CONFIGr(unit, port, rval)); 1757 } 1758 1759 for (index = 0; index < _BCM_TD_NUM_S2_SCHEDULER; index++) { 1760 BCM_IF_ERROR_RETURN 1761 (WRITE_S2_S3_ROUTINGr(unit, port, index, rval64[index])); 1762 } 1763 1764 return BCM_E_NONE; 1765 } 1766 1767 /* 1768 * Function: 1769 * _bcm_td_cosq_node_unresolve 1770 * Purpose: 1771 * Unresolve queue number in the specified scheduler tree and its subtree 1772 * Parameters: 1773 * unit - (IN) unit number 1774 * node - (IN) node structure for the specified scheduler node 1775 * Returns: 1776 * BCM_E_XXX 1777 */ 1778 STATIC int 1779 _bcm_td_cosq_node_unresolve(int unit, _bcm_td_cosq_node_t *node) 1780 { 1781 if (node->cosq_attached_to < 0) { 1782 /* Has been unresolved already */ 1783 return BCM_E_NONE; 1784 } 1785 1786 if (node->child != NULL) { 1787 _bcm_td_cosq_node_unresolve(unit, node->child); 1788 } 1789 1790 if (node->sibling != NULL && node->sibling->cosq_attached_to >= 0) { 1791 _bcm_td_cosq_node_unresolve(unit, node->sibling); 1792 } 1793 1794 node->cosq_attached_to = -1; 1795 node->hw_cosq_attached_to = -1; 1796 node->level = 0; 1797 node->parent = NULL; 1798 node->sibling = NULL; 1799 node->child = NULL; 1800 1801 return BCM_E_NONE; 1802 } 1803 1804 STATIC int 1805 _bcm_td_cosq_config_set(int unit, int numq) 1806 { 1807 port_cos_map_entry_t cos_map_entries[16]; 1808 void *entries[1], *hg_entries[1]; 1809 uint32 index, hg_index; 1810 int count, hg_count; 1811 bcm_port_t port; 1812 int cos, prio; 1813 uint32 i; 1814 #ifdef BCM_COSQ_HIGIG_MAP_DISABLE 1815 port_cos_map_entry_t hg_cos_map_entries[16]; 1816 #endif 1817 1818 if (numq < 1 || numq > 8) { 1819 return BCM_E_PARAM; 1820 } 1821 1822 /* Distribute first 8 internal priority levels into the specified number 1823 * of cosq, map remaining internal priority levels to highest priority 1824 * cosq */ 1825 sal_memset(cos_map_entries, 0, sizeof(cos_map_entries)); 1826 entries[0] = &cos_map_entries; 1827 hg_entries[0] = &cos_map_entries; 1828 prio = 0; 1829 for (cos = 0; cos < numq; cos++) { 1830 for (i = 8 / numq + (cos < 8 % numq ? 1 : 0); i > 0; i--) { 1831 soc_mem_field32_set(unit, PORT_COS_MAPm, &cos_map_entries[prio], 1832 COSf, cos); 1833 prio++; 1834 } 1835 } 1836 for (prio = 8; prio < 16; prio++) { 1837 soc_mem_field32_set(unit, PORT_COS_MAPm, &cos_map_entries[prio], COSf, 1838 numq - 1); 1839 } 1840 1841 /* Map internal priority levels to CPU CoS queues */ 1842 BCM_IF_ERROR_RETURN(_bcm_esw_cpu_cosq_mapping_default_set(unit, numq)); 1843 1844 #ifdef BCM_COSQ_HIGIG_MAP_DISABLE 1845 /* Use identical mapping for Higig port */ 1846 sal_memset(hg_cos_map_entries, 0, sizeof(hg_cos_map_entries)); 1847 hg_entries[0] = &hg_cos_map_entries; 1848 prio = 0; 1849 for (prio = 0; prio < 8; prio++) { 1850 soc_mem_field32_set(unit, PORT_COS_MAPm, &hg_cos_map_entries[prio], 1851 COSf, prio); 1852 } 1853 for (prio = 8; prio < 16; prio++) { 1854 soc_mem_field32_set(unit, PORT_COS_MAPm, &hg_cos_map_entries[prio], 1855 COSf, 7); 1856 } 1857 #endif /* BCM_COSQ_HIGIG_MAP_DISABLE */ 1858 1859 BCM_IF_ERROR_RETURN 1860 (soc_profile_mem_add(unit, _bcm_td_cos_map_profile[unit], entries, 16, 1861 &index)); 1862 BCM_IF_ERROR_RETURN 1863 (soc_profile_mem_add(unit, _bcm_td_cos_map_profile[unit], hg_entries, 1864 16, &hg_index)); 1865 count = 0; 1866 hg_count = 0; 1867 PBMP_ALL_ITER(unit, port) { 1868 if (IS_HG_PORT(unit, port)) { 1869 BCM_IF_ERROR_RETURN 1870 (soc_mem_field32_modify(unit, COS_MAP_SELm, port, SELECTf, 1871 hg_index / 16)); 1872 hg_count++; 1873 } else { 1874 BCM_IF_ERROR_RETURN 1875 (soc_mem_field32_modify(unit, COS_MAP_SELm, port, SELECTf, 1876 index / 16)); 1877 count++; 1878 } 1879 } 1880 if (SOC_INFO(unit).cpu_hg_index != -1) { 1881 BCM_IF_ERROR_RETURN 1882 (soc_mem_field32_modify(unit, COS_MAP_SELm, 1883 SOC_INFO(unit).cpu_hg_index, SELECTf, 1884 hg_index / 16)); 1885 hg_count++; 1886 } 1887 for (i = 1; i < count; i++) { 1888 soc_profile_mem_reference(unit, _bcm_td_cos_map_profile[unit], index, 1889 0); 1890 } 1891 for (i = 1; i < hg_count; i++) { 1892 soc_profile_mem_reference(unit, _bcm_td_cos_map_profile[unit], 1893 hg_index, 0); 1894 } 1895 1896 _bcm_td_num_cosq[unit] = numq; 1897 1898 return BCM_E_NONE; 1899 } 1900 1901 /* 1902 * Function: 1903 * _bcm_td_cosq_mapping_set 1904 * Purpose: 1905 * Set COS queue for the specified priority of an ingress port 1906 * Parameters: 1907 * unit - (IN) unit number 1908 * ing_port - (IN) ingress port 1909 * gport - (IN) queue group GPORT identifier 1910 * priority - (IN) priority value to map 1911 * flags - (IN) BCM_COSQ_GPORT_XXX_QUEUE_GROUP 1912 * gport - (IN) queue group GPORT identifier 1913 * cosq - (IN) COS queue number 1914 * Returns: 1915 * BCM_E_XXX 1916 */ 1917 int 1918 _bcm_td_cosq_mapping_set(int unit, bcm_port_t ing_port, bcm_cos_t priority, 1919 uint32 flags, bcm_gport_t gport, bcm_cos_queue_t cosq) 1920 { 1921 bcm_port_t local_port; 1922 bcm_cos_queue_t hw_cosq, mc_hw_cosq = 0; 1923 soc_field_t field, field2 = INVALIDf; 1924 cos_map_sel_entry_t cos_map_sel_entry; 1925 port_cos_map_entry_t cos_map_entries[16]; 1926 void *entries[1]; 1927 uint32 old_index, new_index; 1928 int rv; 1929 1930 if (priority < 0 || priority >= 16) { 1931 return BCM_E_PARAM; 1932 } 1933 1934 BCM_IF_ERROR_RETURN 1935 (_bcm_td_cosq_localport_resolve(unit, ing_port, &local_port)); 1936 1937 switch (flags) { 1938 case BCM_COSQ_GPORT_UCAST_QUEUE_GROUP: 1939 if (gport == -1) { 1940 hw_cosq = cosq; 1941 } else { 1942 BCM_IF_ERROR_RETURN 1943 (_bcm_td_cosq_index_resolve 1944 (unit, gport, cosq, _BCM_TD_COSQ_INDEX_STYLE_UCAST_QUEUE, 1945 NULL, &hw_cosq, NULL)); 1946 } 1947 field = UC_COS1f; 1948 break; 1949 case BCM_COSQ_GPORT_MCAST_QUEUE_GROUP: 1950 if (gport == -1) { 1951 hw_cosq = cosq; 1952 } else { 1953 BCM_IF_ERROR_RETURN 1954 (_bcm_td_cosq_index_resolve 1955 (unit, gport, cosq, _BCM_TD_COSQ_INDEX_STYLE_MCAST_QUEUE, 1956 NULL, &hw_cosq, NULL)); 1957 } 1958 field = MC_COS1f; 1959 break; 1960 case BCM_COSQ_GPORT_UCAST_QUEUE_GROUP | BCM_COSQ_GPORT_MCAST_QUEUE_GROUP: 1961 if (gport == -1) { 1962 hw_cosq = (cosq >> 16) & 0xffff; 1963 mc_hw_cosq = cosq & 0xffff; 1964 } else { 1965 return BCM_E_PARAM; 1966 } 1967 field = UC_COS1f; 1968 field2 = MC_COS1f; 1969 break; 1970 case BCM_COSQ_GPORT_DESTMOD_UCAST_QUEUE_GROUP: 1971 if (gport == -1) { 1972 return BCM_E_UNAVAIL; 1973 } else { 1974 BCM_IF_ERROR_RETURN 1975 (_bcm_td_cosq_index_resolve 1976 (unit, gport, cosq, _BCM_TD_COSQ_INDEX_STYLE_EXT_UCAST_QUEUE, 1977 NULL, &hw_cosq, NULL)); 1978 } 1979 field = HG_COSf; 1980 break; 1981 default: 1982 return BCM_E_PARAM; 1983 } 1984 1985 /* There are only 5 MC QUEUES [0,4] attached to a port. */ 1986 if (flags == BCM_COSQ_GPORT_MCAST_QUEUE_GROUP) { 1987 if (hw_cosq > (_BCM_TD_NUM_MCAST_QUEUE_GROUP - 1)) { 1988 return BCM_E_PARAM; 1989 } 1990 } 1991 1992 entries[0] = &cos_map_entries; 1993 1994 BCM_IF_ERROR_RETURN 1995 (READ_COS_MAP_SELm(unit, MEM_BLOCK_ANY, local_port, 1996 &cos_map_sel_entry)); 1997 old_index = soc_mem_field32_get(unit, COS_MAP_SELm, &cos_map_sel_entry, 1998 SELECTf); 1999 old_index *= 16; 2000 2001 BCM_IF_ERROR_RETURN 2002 (soc_profile_mem_get(unit, _bcm_td_cos_map_profile[unit], 2003 old_index, 16, entries)); 2004 soc_mem_field32_set(unit, PORT_COS_MAPm, &cos_map_entries[priority], field, 2005 hw_cosq); 2006 if (field2 != INVALIDf) { 2007 soc_mem_field32_set(unit, PORT_COS_MAPm, &cos_map_entries[priority], 2008 field2,mc_hw_cosq); 2009 } 2010 2011 soc_mem_lock(unit, PORT_COS_MAPm); 2012 2013 rv = soc_profile_mem_delete(unit, _bcm_td_cos_map_profile[unit], 2014 old_index); 2015 #ifndef BCM_COSQ_HIGIG_MAP_DISABLE 2016 if (BCM_SUCCESS(rv) && IS_CPU_PORT(unit, local_port)) { 2017 rv = soc_profile_mem_delete(unit, _bcm_td_cos_map_profile[unit], 2018 old_index); 2019 } 2020 #endif /* BCM_COSQ_HIGIG_MAP_DISABLE */ 2021 if (BCM_FAILURE(rv)) { 2022 soc_mem_unlock(unit, PORT_COS_MAPm); 2023 return rv; 2024 } 2025 2026 rv = soc_profile_mem_add(unit, _bcm_td_cos_map_profile[unit], entries, 2027 16, &new_index); 2028 #ifndef BCM_COSQ_HIGIG_MAP_DISABLE 2029 if (BCM_SUCCESS(rv) && IS_CPU_PORT(unit, local_port)) { 2030 rv = soc_profile_mem_reference(unit, _bcm_td_cos_map_profile[unit], 2031 new_index, 16); 2032 } 2033 #endif /* BCM_COSQ_HIGIG_MAP_DISABLE */ 2034 2035 if (rv == SOC_E_RESOURCE) { 2036 (void)soc_profile_mem_reference(unit, _bcm_td_cos_map_profile[unit], 2037 old_index, 16); 2038 #ifndef BCM_COSQ_HIGIG_MAP_DISABLE 2039 if (IS_CPU_PORT(unit, local_port)) { 2040 (void)soc_profile_mem_reference(unit, 2041 _bcm_td_cos_map_profile[unit], 2042 old_index, 16); 2043 } 2044 #endif /* BCM_COSQ_HIGIG_MAP_DISABLE */ 2045 } 2046 2047 soc_mem_unlock(unit, PORT_COS_MAPm); 2048 2049 if (BCM_FAILURE(rv)) { 2050 return rv; 2051 } 2052 2053 soc_mem_field32_set(unit, COS_MAP_SELm, &cos_map_sel_entry, SELECTf, 2054 new_index / 16); 2055 BCM_IF_ERROR_RETURN 2056 (WRITE_COS_MAP_SELm(unit, MEM_BLOCK_ANY, local_port, 2057 &cos_map_sel_entry)); 2058 2059 #ifndef BCM_COSQ_HIGIG_MAP_DISABLE 2060 if (IS_CPU_PORT(unit, local_port)) { 2061 BCM_IF_ERROR_RETURN 2062 (soc_mem_field32_modify(unit, COS_MAP_SELm, 2063 SOC_INFO(unit).cpu_hg_index, SELECTf, 2064 new_index / 16)); 2065 } 2066 #endif /* BCM_COSQ_HIGIG_MAP_DISABLE */ 2067 2068 if (flags == BCM_COSQ_GPORT_DESTMOD_UCAST_QUEUE_GROUP) { 2069 BCM_IF_ERROR_RETURN 2070 (_bcm_td_voq_gport_mapping_set(unit, gport, priority, cosq)); 2071 } 2072 2073 return BCM_E_NONE; 2074 } 2075 2076 /* 2077 * Function: 2078 * _bcm_td_cosq_mapping_get 2079 * Purpose: 2080 * Get COS queue for the specified priority of an ingress port 2081 * Parameters: 2082 * unit - (IN) unit number 2083 * ing_port - (IN) ingress port 2084 * gport - (IN) queue group GPORT identifier 2085 * priority - (IN) priority value to map 2086 * flags - (IN) BCM_COSQ_GPORT_XXX_QUEUE_GROUP 2087 * gport - (OUT) queue group GPORT identifier 2088 * cosq - (OUT) COS queue number 2089 * Returns: 2090 * BCM_E_XXX 2091 */ 2092 int 2093 _bcm_td_cosq_mapping_get(int unit, bcm_port_t ing_port, bcm_cos_t priority, 2094 uint32 flags, bcm_gport_t *gport, 2095 bcm_cos_queue_t *cosq) 2096 { 2097 _bcm_td_cosq_port_info_t *port_info; 2098 _bcm_td_cosq_node_t *node; 2099 bcm_port_t local_port; 2100 bcm_cos_queue_t hw_cosq; 2101 int index, i; 2102 cos_map_sel_entry_t cos_map_sel_entry; 2103 void *entry_p; 2104 2105 if (priority < 0 || priority >= 16) { 2106 return BCM_E_PARAM; 2107 } 2108 2109 if (flags != BCM_COSQ_GPORT_UCAST_QUEUE_GROUP && 2110 flags != BCM_COSQ_GPORT_MCAST_QUEUE_GROUP && 2111 flags != BCM_COSQ_GPORT_DESTMOD_UCAST_QUEUE_GROUP) { 2112 return BCM_E_PARAM; 2113 } 2114 2115 BCM_IF_ERROR_RETURN 2116 (_bcm_td_cosq_localport_resolve(unit, ing_port, &local_port)); 2117 2118 BCM_IF_ERROR_RETURN 2119 (READ_COS_MAP_SELm(unit, MEM_BLOCK_ANY, local_port, 2120 &cos_map_sel_entry)); 2121 index = soc_mem_field32_get(unit, COS_MAP_SELm, &cos_map_sel_entry, 2122 SELECTf); 2123 index *= 16; 2124 2125 entry_p = SOC_PROFILE_MEM_ENTRY(unit, _bcm_td_cos_map_profile[unit], 2126 port_cos_map_entry_t *, 2127 index + priority); 2128 2129 switch (flags) { 2130 case BCM_COSQ_GPORT_UCAST_QUEUE_GROUP: 2131 hw_cosq = soc_mem_field32_get(unit, PORT_COS_MAPm, entry_p, UC_COS1f); 2132 if (IS_CPU_PORT(unit, local_port) || IS_LB_PORT(unit, local_port) || 2133 !gport) { 2134 if (gport) { 2135 *gport = BCM_GPORT_INVALID; 2136 } 2137 *cosq = hw_cosq; 2138 } else { 2139 port_info = &_bcm_td_cosq_port_info[unit][local_port]; 2140 for (i = 0; i < _BCM_TD_NUM_UCAST_QUEUE_GROUP; i++) { 2141 node = &port_info->ucast[i]; 2142 if (node->numq > 0 && node->base == hw_cosq) { 2143 *gport = node->gport; 2144 *cosq = 0; 2145 break; 2146 } 2147 } 2148 if (i == _BCM_TD_NUM_UCAST_QUEUE_GROUP) { 2149 return BCM_E_NOT_FOUND; 2150 } 2151 } 2152 break; 2153 case BCM_COSQ_GPORT_MCAST_QUEUE_GROUP: 2154 hw_cosq = soc_mem_field32_get(unit, PORT_COS_MAPm, entry_p, MC_COS1f); 2155 if (IS_CPU_PORT(unit, local_port) || IS_LB_PORT(unit, local_port) || 2156 !gport) { 2157 if (gport) { 2158 *gport = BCM_GPORT_INVALID; 2159 } 2160 *cosq = hw_cosq; 2161 } else { 2162 port_info = &_bcm_td_cosq_port_info[unit][local_port]; 2163 for (i = 0; i < _BCM_TD_NUM_MCAST_QUEUE_GROUP; i++) { 2164 node = &port_info->mcast[i]; 2165 if (node->numq > 0 && node->base == hw_cosq) { 2166 *gport = node->gport; 2167 *cosq = 0; 2168 break; 2169 } 2170 } 2171 if (i == _BCM_TD_NUM_MCAST_QUEUE_GROUP) { 2172 return BCM_E_NOT_FOUND; 2173 } 2174 } 2175 break; 2176 case BCM_COSQ_GPORT_DESTMOD_UCAST_QUEUE_GROUP: 2177 hw_cosq = soc_mem_field32_get(unit, PORT_COS_MAPm, entry_p, HG_COSf); 2178 if (IS_CPU_PORT(unit, local_port) || IS_LB_PORT(unit, local_port) || 2179 !gport) { 2180 if (gport) { 2181 *gport = BCM_GPORT_INVALID; 2182 } 2183 *cosq = hw_cosq; 2184 } else { 2185 port_info = &_bcm_td_cosq_port_info[unit][local_port]; 2186 for (i = 0; i < _BCM_TD_NUM_EXT_UCAST_QUEUE_GROUP; i++) { 2187 node = &port_info->ext_ucast[i]; 2188 if (node->numq > 0 && node->base == hw_cosq % 16) { 2189 *gport = node->gport; 2190 *cosq = hw_cosq / 16; 2191 break; 2192 } 2193 } 2194 if (i == _BCM_TD_NUM_EXT_UCAST_QUEUE_GROUP) { 2195 return BCM_E_NOT_FOUND; 2196 } 2197 } 2198 break; 2199 } 2200 2201 return BCM_E_NONE; 2202 } 2203 2204 /* 2205 * Convert HW drop probability to percent value 2206 */ 2207 STATIC int 2208 _bcm_td_hw_drop_prob_to_percent[] = { 2209 0, /* 0 */ 2210 1, /* 1 */ 2211 2, /* 2 */ 2212 3, /* 3 */ 2213 4, /* 4 */ 2214 5, /* 5 */ 2215 6, /* 6 */ 2216 7, /* 7 */ 2217 8, /* 8 */ 2218 9, /* 9 */ 2219 10, /* 10 */ 2220 25, /* 11 */ 2221 50, /* 12 */ 2222 75, /* 13 */ 2223 100, /* 14 */ 2224 -1 /* 15 */ 2225 }; 2226 2227 STATIC int 2228 _bcm_td_percent_to_drop_prob(int percent) 2229 { 2230 int i; 2231 2232 for (i = 14; i > 0 ; i--) { 2233 if (percent >= _bcm_td_hw_drop_prob_to_percent[i]) { 2234 break; 2235 } 2236 } 2237 return i; 2238 } 2239 2240 STATIC int 2241 _bcm_td_drop_prob_to_percent(int drop_prob) { 2242 return (_bcm_td_hw_drop_prob_to_percent[drop_prob]); 2243 } 2244 2245 /* 2246 * index: degree, value: contangent(degree) * 100 2247 * max value is 0xffff (16-bit) at 0 degree 2248 */ 2249 STATIC int 2250 _bcm_td_cotangent_lookup_table[] = 2251 { 2252 /* 0.. 5 */ 65535, 5728, 2863, 1908, 1430, 1143, 2253 /* 6..11 */ 951, 814, 711, 631, 567, 514, 2254 /* 12..17 */ 470, 433, 401, 373, 348, 327, 2255 /* 18..23 */ 307, 290, 274, 260, 247, 235, 2256 /* 24..29 */ 224, 214, 205, 196, 188, 180, 2257 /* 30..35 */ 173, 166, 160, 153, 148, 142, 2258 /* 36..41 */ 137, 132, 127, 123, 119, 115, 2259 /* 42..47 */ 111, 107, 103, 100, 96, 93, 2260 /* 48..53 */ 90, 86, 83, 80, 78, 75, 2261 /* 54..59 */ 72, 70, 67, 64, 62, 60, 2262 /* 60..65 */ 57, 55, 53, 50, 48, 46, 2263 /* 66..71 */ 44, 42, 40, 38, 36, 34, 2264 /* 72..77 */ 32, 30, 28, 26, 24, 23, 2265 /* 78..83 */ 21, 19, 17, 15, 14, 12, 2266 /* 84..89 */ 10, 8, 6, 5, 3, 1, 2267 /* 90 */ 0 2268 }; 2269 2270 /* 2271 * Given a slope (angle in degrees) from 0 to 90, return the number of cells 2272 * in the range from 0% drop probability to 100% drop probability. 2273 */ 2274 STATIC int 2275 _bcm_td_angle_to_cells(int angle) 2276 { 2277 return (_bcm_td_cotangent_lookup_table[angle]); 2278 } 2279 2280 /* 2281 * Given a number of packets in the range from 0% drop probability 2282 * to 100% drop probability, return the slope (angle in degrees). 2283 */ 2284 STATIC int 2285 _bcm_td_cells_to_angle(int packets) 2286 { 2287 int angle; 2288 2289 for (angle = 90; angle >= 0 ; angle--) { 2290 if (packets <= _bcm_td_cotangent_lookup_table[angle]) { 2291 break; 2292 } 2293 } 2294 return angle; 2295 } 2296 2297 STATIC int 2298 _bcm_td_cosq_refresh_freeze(int unit) 2299 { 2300 uint32 reg; 2301 int rv = BCM_E_NONE; 2302 2303 if (soc_feature(unit, soc_feature_bucket_update_freeze)) { 2304 TD_COSQ_LOCK(unit); 2305 2306 rv = READ_MISCCONFIGr(unit, ®); 2307 if (BCM_FAILURE(rv)) { 2308 TD_COSQ_UNLOCK(unit); 2309 return rv; 2310 } 2311 soc_reg_field_set(unit, MISCCONFIGr, ®, REFRESH_ENf, 0); 2312 rv = WRITE_MISCCONFIGr(unit, reg); 2313 if (BCM_FAILURE(rv)) { 2314 TD_COSQ_UNLOCK(unit); 2315 return rv; 2316 } 2317 } 2318 2319 return rv; 2320 } 2321 2322 STATIC int 2323 _bcm_td_cosq_refresh_thaw(int unit) 2324 { 2325 uint32 reg; 2326 int rv = BCM_E_NONE; 2327 2328 if (soc_feature(unit, soc_feature_bucket_update_freeze)) { 2329 rv = READ_MISCCONFIGr(unit, ®); 2330 if (BCM_FAILURE(rv)) { 2331 TD_COSQ_UNLOCK(unit); 2332 return rv; 2333 } 2334 soc_reg_field_set(unit, MISCCONFIGr, ®, REFRESH_ENf, 1); 2335 rv = WRITE_MISCCONFIGr(unit, reg); 2336 if (BCM_FAILURE(rv)) { 2337 TD_COSQ_UNLOCK(unit); 2338 return rv; 2339 } 2340 2341 TD_COSQ_UNLOCK(unit); 2342 } 2343 2344 return rv; 2345 } 2346 2347 /* 2348 * Function: 2349 * _bcm_td_cosq_bucket_set 2350 * Purpose: 2351 * Configure COS queue bandwidth control bucket 2352 * Parameters: 2353 * unit - (IN) unit number 2354 * port - (IN) port number or GPORT identifier 2355 * cosq - (IN) COS queue number 2356 * min_bandwidth - (IN) min bucket bandwidth (kbps or packet/second) 2357 * max_bandwidth - (IN) max bucket bandwidth (kbps or packet/second) 2358 * min_burst - (IN) min bucket burst size (kbits or packets) 2359 * max_burst - (IN) max bucket burst size (kbits or packets) 2360 * flags - (IN) BCM_COSQ_BW_PACKET_MODE_XXX 2361 * Returns: 2362 * BCM_E_XXX 2363 * Notes: 2364 * If port is any form of local port, cosq is the hardware queue index. 2365 */ 2366 STATIC int 2367 _bcm_td_cosq_bucket_set(int unit, bcm_gport_t port, bcm_cos_queue_t cosq, 2368 uint32 min_bandwidth, uint32 max_bandwidth, 2369 uint32 min_burst, uint32 max_burst, 2370 uint32 flags) 2371 { 2372 soc_info_t *si; 2373 _bcm_td_cosq_node_t *node; 2374 bcm_port_t local_port, mmu_port, mmu_cmic_port, mmu_lb_port; 2375 int rv, index; 2376 soc_reg_t max_config_reg, max_reg, min_config_reg, min_reg, shaping_reg; 2377 uint32 rval, fval; 2378 uint32 orig_bandwidth, orig_burst; 2379 uint64 rval64, orig_rval64, bucket_rval64, mode_rval64; 2380 uint32 refresh_rate, bucketsize, granularity, meter_flags; 2381 int refresh_bitsize, bucket_bitsize; 2382 static const soc_reg_t ext_shaping_reg_x[] = { 2383 EXT1_SHAPING_CONTROL_PORT1r, EXT1_SHAPING_CONTROL_PORT2r, 2384 EXT1_SHAPING_CONTROL_PORT3r, EXT1_SHAPING_CONTROL_PORT4r 2385 }; 2386 static const soc_reg_t ext_shaping_reg_y[] = { 2387 EXT1_SHAPING_CONTROL_PORT34r, EXT1_SHAPING_CONTROL_PORT35r, 2388 EXT1_SHAPING_CONTROL_PORT36r, EXT1_SHAPING_CONTROL_PORT37r 2389 }; 2390 2391 if (cosq < 0) { 2392 if (cosq == -1) { 2393 /* caller needs to resolve the wild card value (-1) */ 2394 return BCM_E_INTERNAL; 2395 } else { /* reject all other negative value */ 2396 return BCM_E_PARAM; 2397 } 2398 } 2399 2400 BCM_IF_ERROR_RETURN 2401 (_bcm_td_cosq_index_resolve(unit, port, cosq, 2402 _BCM_TD_COSQ_INDEX_STYLE_BUCKET, 2403 &local_port, &index, NULL)); 2404 2405 if (BCM_GPORT_IS_SCHEDULER(port)) { 2406 BCM_IF_ERROR_RETURN 2407 (_bcm_td_cosq_node_get(unit, port, NULL, NULL, NULL, &node)); 2408 if (node->level == 3) { /* S3 scheduler */ 2409 max_config_reg = S3_MAXBUCKETCONFIG_64r; 2410 max_reg = S3_MAXBUCKETr; 2411 min_config_reg = S3_MINBUCKETCONFIG_64r; 2412 min_reg = S3_MINBUCKETr; 2413 } else if (node->level == 2) { /* S2 scheduler */ 2414 max_config_reg = S2_MAXBUCKETCONFIG_64r; 2415 max_reg = S2_MAXBUCKETr; 2416 min_config_reg = S2_MINBUCKETCONFIG_64r; 2417 min_reg = S2_MINBUCKETr; 2418 } else { 2419 return BCM_E_PARAM; 2420 } 2421 } else if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port) || 2422 BCM_GPORT_IS_MCAST_QUEUE_GROUP(port)) { 2423 max_config_reg = MAXBUCKETCONFIG_64r; 2424 max_reg = MAXBUCKETr; 2425 min_config_reg = MINBUCKETCONFIG_64r; 2426 min_reg = MINBUCKETr; 2427 } else { /* local port */ 2428 if (cosq < _BCM_TD_NUM_S3_SCHEDULER && 2429 !IS_CPU_PORT(unit, local_port)) { 2430 /* use S3.0 - S3.3 for unicast and multicast queue 0 - 3 */ 2431 max_config_reg = S3_MAXBUCKETCONFIG_64r; 2432 max_reg = S3_MAXBUCKETr; 2433 min_config_reg = S3_MINBUCKETCONFIG_64r; 2434 min_reg = S3_MINBUCKETr; 2435 } else { /* unicast queue 4 - 7 */ 2436 max_config_reg = MAXBUCKETCONFIG_64r; 2437 max_reg = MAXBUCKETr; 2438 min_config_reg = MINBUCKETCONFIG_64r; 2439 min_reg = MINBUCKETr; 2440 } 2441 } 2442 2443 meter_flags = flags & BCM_COSQ_BW_PACKET_MODE ? 2444 _BCM_TD_METER_FLAG_PACKET_MODE : 0; 2445 BCM_IF_ERROR_RETURN(READ_MISCCONFIGr(unit, &rval)); 2446 if (soc_reg_field_get(unit, MISCCONFIGr, rval, ITU_MODE_SELf)) { 2447 meter_flags |= _BCM_TD_METER_FLAG_NON_LINEAR; 2448 } 2449 2450 /* Retrieve MAXBUCKETCONFIG_64 and max bucket size */ 2451 BCM_IF_ERROR_RETURN(_bcm_td_cosq_refresh_freeze(unit)); 2452 BCM_IF_ERROR_RETURN 2453 (soc_reg_get(unit, max_config_reg, local_port, index, &orig_rval64)); 2454 BCM_IF_ERROR_RETURN(_bcm_td_cosq_refresh_thaw(unit)); 2455 granularity = 2456 soc_reg64_field32_get(unit, max_config_reg, orig_rval64, METER_GRANf); 2457 refresh_rate = 2458 soc_reg64_field32_get(unit, max_config_reg, orig_rval64, MAX_REFRESHf); 2459 bucketsize = 2460 soc_reg64_field32_get(unit, max_config_reg, orig_rval64, MAX_THDf); 2461 BCM_IF_ERROR_RETURN 2462 (_bcm_td_bucket_encoding_to_rate(unit, refresh_rate, bucketsize, 2463 granularity, meter_flags, 2464 &orig_bandwidth, &orig_burst)); 2465 2466 /* Construct MAXBUCKETCONFIG_64 */ 2467 refresh_bitsize = soc_reg_field_length(unit, max_config_reg, MAX_REFRESHf); 2468 bucket_bitsize = soc_reg_field_length(unit, max_config_reg, MAX_THDf); 2469 BCM_IF_ERROR_RETURN 2470 (_bcm_td_rate_to_bucket_encoding(unit, max_bandwidth, max_burst, 2471 meter_flags, refresh_bitsize, 2472 bucket_bitsize, &refresh_rate, 2473 &bucketsize, &granularity)); 2474 COMPILER_64_ZERO(rval64); 2475 soc_reg64_field32_set(unit, max_config_reg, &rval64, METER_GRANf, 2476 granularity); 2477 soc_reg64_field32_set(unit, max_config_reg, &rval64, MAX_REFRESHf, 2478 refresh_rate); 2479 soc_reg64_field32_set(unit, max_config_reg, &rval64, MAX_THDf, bucketsize); 2480 2481 if (COMPILER_64_NE(rval64, orig_rval64)) { /* value changed */ 2482 if (orig_burst != max_burst) { 2483 /* Construct MAXBUCKET, pre-fill it to the current bucket size */ 2484 COMPILER_64_ZERO(bucket_rval64); 2485 if (meter_flags & _BCM_TD_METER_FLAG_NON_LINEAR) { 2486 fval = ((bucketsize & 0xff) + 256) << ((bucketsize >> 8) + 8); 2487 } else { 2488 fval = bucketsize << 16; 2489 } 2490 soc_reg64_field32_set(unit, max_reg, &bucket_rval64, MAX_BUCKETf, 2491 fval); 2492 2493 BCM_IF_ERROR_RETURN(_bcm_td_cosq_refresh_freeze(unit)); 2494 /* Write MAXBUCKETCONFIG */ 2495 rv = soc_reg_set(unit, max_config_reg, local_port, index, rval64); 2496 if (BCM_SUCCESS(rv)) { 2497 /* Write MAXBUCKET */ 2498 rv =soc_reg_set(unit, max_reg, local_port, index, 2499 bucket_rval64); 2500 } 2501 BCM_IF_ERROR_RETURN(_bcm_td_cosq_refresh_thaw(unit)); 2502 if (BCM_FAILURE(rv)) { 2503 return rv; 2504 } 2505 } else { 2506 /* Write the constructed value to hardware */ 2507 BCM_IF_ERROR_RETURN(soc_reg_set(unit, max_config_reg, local_port, 2508 index, rval64)); 2509 } 2510 } 2511 2512 /* Retrieve MINBUCKETCONFIG_64 and min bucket size */ 2513 BCM_IF_ERROR_RETURN 2514 (soc_reg_get(unit, min_config_reg, local_port, index, &orig_rval64)); 2515 granularity = 2516 soc_reg64_field32_get(unit, min_config_reg, orig_rval64, METER_GRANf); 2517 refresh_rate = 2518 soc_reg64_field32_get(unit, min_config_reg, orig_rval64, MIN_REFRESHf); 2519 bucketsize = 2520 soc_reg64_field32_get(unit, min_config_reg, orig_rval64, MIN_THDf); 2521 BCM_IF_ERROR_RETURN 2522 (_bcm_td_bucket_encoding_to_rate(unit, refresh_rate, bucketsize, 2523 granularity, meter_flags, 2524 &orig_bandwidth, &orig_burst)); 2525 2526 /* Construct MINBUCKETCONFIG_64 */ 2527 refresh_bitsize = soc_reg_field_length(unit, min_config_reg, MIN_REFRESHf); 2528 bucket_bitsize = soc_reg_field_length(unit, min_config_reg, MIN_THDf); 2529 BCM_IF_ERROR_RETURN 2530 (_bcm_td_rate_to_bucket_encoding(unit, min_bandwidth, min_burst, 2531 meter_flags, refresh_bitsize, 2532 bucket_bitsize, &refresh_rate, 2533 &bucketsize, &granularity)); 2534 COMPILER_64_ZERO(rval64); 2535 soc_reg64_field32_set(unit, min_config_reg, &rval64, METER_GRANf, 2536 granularity); 2537 soc_reg64_field32_set(unit, min_config_reg, &rval64, MIN_REFRESHf, 2538 refresh_rate); 2539 soc_reg64_field32_set(unit, min_config_reg, &rval64, MIN_THDf, bucketsize); 2540 2541 if (COMPILER_64_NE(rval64, orig_rval64)) { /* value changed */ 2542 if (orig_burst != min_burst) { 2543 /* Construct MINBUCKET, pre-fill it to the current bucket size */ 2544 COMPILER_64_ZERO(bucket_rval64); 2545 if (meter_flags & _BCM_TD_METER_FLAG_NON_LINEAR) { 2546 fval = ((bucketsize & 0xff) + 256) << ((bucketsize >> 8) + 8); 2547 } else { 2548 fval = bucketsize << 16; 2549 } 2550 soc_reg64_field32_set(unit, min_reg, &bucket_rval64, MIN_BUCKETf, 2551 fval); 2552 2553 BCM_IF_ERROR_RETURN(_bcm_td_cosq_refresh_freeze(unit)); 2554 /* Write MINBUCKETCONFIG */ 2555 rv = soc_reg_set(unit, min_config_reg, local_port, index, rval64); 2556 if (BCM_SUCCESS(rv)) { 2557 /* Write MINBUCKET */ 2558 rv =soc_reg_set(unit, min_reg, local_port, index, 2559 bucket_rval64); 2560 } 2561 BCM_IF_ERROR_RETURN(_bcm_td_cosq_refresh_thaw(unit)); 2562 if (BCM_FAILURE(rv)) { 2563 return rv; 2564 } 2565 } else { 2566 /* Write the constructed value to hardware */ 2567 BCM_IF_ERROR_RETURN(soc_reg_set(unit, min_config_reg, local_port, 2568 index, rval64)); 2569 } 2570 } 2571 2572 /* resolve index into SHAPING_CONTROL register */ 2573 BCM_IF_ERROR_RETURN 2574 (_bcm_td_cosq_index_resolve(unit, port, cosq, 2575 _BCM_TD_COSQ_INDEX_STYLE_BUCKET_MODE, 2576 NULL, &index, NULL)); 2577 2578 /* Configure SHAPING_CONTROL */ 2579 if (index < 48) { /* in SHAPING_CONTROL */ 2580 shaping_reg = SHAPING_CONTROLr; 2581 } else { /* in EXT1_SHAPING_CONTROL_PORTx */ 2582 index -= 48; 2583 si = &SOC_INFO(unit); 2584 mmu_cmic_port = 2585 si->port_p2m_mapping[si->port_l2p_mapping[si->cmic_port]]; 2586 mmu_lb_port = si->port_p2m_mapping[si->port_l2p_mapping[si->lb_port]]; 2587 mmu_port = si->port_p2m_mapping[si->port_l2p_mapping[local_port]]; 2588 if (mmu_port < mmu_lb_port) { /* X pipe */ 2589 shaping_reg = ext_shaping_reg_x[mmu_port - mmu_cmic_port - 1]; 2590 } else { /* Y pipe */ 2591 shaping_reg = ext_shaping_reg_y[mmu_port - mmu_lb_port - 1]; 2592 } 2593 } 2594 2595 /* Retrieve SHAPING_CONTROL */ 2596 BCM_IF_ERROR_RETURN 2597 (soc_reg_get(unit, shaping_reg, local_port, 0, &orig_rval64)); 2598 2599 /* Construct SHAPING_CONTROL */ 2600 if (index < 32) { 2601 COMPILER_64_SET(mode_rval64, 0, 1 << index); 2602 } else { 2603 COMPILER_64_SET(mode_rval64, 1 << (index - 32), 0); 2604 } 2605 rval64 = orig_rval64; 2606 if (flags & BCM_COSQ_BW_PACKET_MODE) { 2607 COMPILER_64_OR(rval64, mode_rval64); 2608 } else { 2609 COMPILER_64_NOT(mode_rval64); 2610 COMPILER_64_AND(rval64, mode_rval64); 2611 } 2612 2613 /* Write the constructed value to SHAPING_CONTROL hardware */ 2614 if (COMPILER_64_NE(rval64, orig_rval64)) { 2615 BCM_IF_ERROR_RETURN 2616 (soc_reg_set(unit, shaping_reg, local_port, 0, rval64)); 2617 } 2618 2619 return BCM_E_NONE; 2620 } 2621 2622 /* 2623 * Function: 2624 * _bcm_td_cosq_bucket_get 2625 * Purpose: 2626 * Get COS queue bandwidth control bucket setting 2627 * Parameters: 2628 * unit - (IN) unit number 2629 * port - (IN) port number or GPORT identifier 2630 * cosq - (IN) COS queue number 2631 * min_bandwidth - (OUT) min bucket bandwidth (kbps or packet/second) 2632 * max_bandwidth - (OUT) max bucket bandwidth (kbps or packet/second) 2633 * min_burst - (OUT) min bucket burst size (kbits or packets) 2634 * max_burst - (OUT) max bucket burst size (kbits or packets) 2635 * flags - (OUT) BCM_COSQ_BW_PACKET_MODE_XXX 2636 * Returns: 2637 * BCM_E_XXX 2638 * Notes: 2639 * If port is any form of local port, cosq is the hardware queue index. 2640 */ 2641 STATIC int 2642 _bcm_td_cosq_bucket_get(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 2643 uint32 *min_bandwidth, uint32 *max_bandwidth, 2644 uint32 *min_burst, uint32 *max_burst, 2645 uint32 *flags) 2646 { 2647 soc_info_t *si; 2648 _bcm_td_cosq_node_t *node; 2649 bcm_port_t local_port, mmu_port, mmu_cmic_port, mmu_lb_port; 2650 int index, rv; 2651 soc_reg_t max_config_reg, min_config_reg, shaping_reg; 2652 uint32 rval; 2653 uint64 rval64; 2654 uint32 refresh_rate, bucketsize, granularity, meter_flags; 2655 static const soc_reg_t ext_shaping_reg_x[] = { 2656 EXT1_SHAPING_CONTROL_PORT1r, EXT1_SHAPING_CONTROL_PORT2r, 2657 EXT1_SHAPING_CONTROL_PORT3r, EXT1_SHAPING_CONTROL_PORT4r 2658 }; 2659 static const soc_reg_t ext_shaping_reg_y[] = { 2660 EXT1_SHAPING_CONTROL_PORT34r, EXT1_SHAPING_CONTROL_PORT35r, 2661 EXT1_SHAPING_CONTROL_PORT36r, EXT1_SHAPING_CONTROL_PORT37r 2662 }; 2663 2664 if (cosq < 0) { 2665 if (cosq == -1) { 2666 /* caller needs to resolve the wild card value (-1) */ 2667 return BCM_E_INTERNAL; 2668 } else { /* reject all other negative value */ 2669 return BCM_E_PARAM; 2670 } 2671 } 2672 2673 if (min_bandwidth == NULL || max_bandwidth == NULL || 2674 min_burst == NULL || max_burst == NULL || flags == NULL) { 2675 return BCM_E_PARAM; 2676 } 2677 2678 BCM_IF_ERROR_RETURN 2679 (_bcm_td_cosq_index_resolve(unit, port, cosq, 2680 _BCM_TD_COSQ_INDEX_STYLE_BUCKET_MODE, 2681 &local_port, &index, NULL)); 2682 2683 if (index < 48) { /* in SHAPING_CONTROL */ 2684 shaping_reg = SHAPING_CONTROLr; 2685 } else { /* in EXT1_SHAPING_CONTROL_PORTx */ 2686 index -= 48; 2687 si = &SOC_INFO(unit); 2688 mmu_cmic_port = 2689 si->port_p2m_mapping[si->port_l2p_mapping[si->cmic_port]]; 2690 mmu_lb_port = si->port_p2m_mapping[si->port_l2p_mapping[si->lb_port]]; 2691 mmu_port = si->port_p2m_mapping[si->port_l2p_mapping[local_port]]; 2692 if (mmu_port < mmu_lb_port) { /* X pipe */ 2693 shaping_reg = ext_shaping_reg_x[mmu_port - mmu_cmic_port - 1]; 2694 } else { /* Y pipe */ 2695 shaping_reg = ext_shaping_reg_y[mmu_port - mmu_lb_port - 1]; 2696 } 2697 } 2698 BCM_IF_ERROR_RETURN 2699 (soc_reg_get(unit, shaping_reg, local_port, 0, &rval64)); 2700 if (index < 32) { 2701 *flags = COMPILER_64_LO(rval64) & (1 << index) ? 2702 BCM_COSQ_BW_PACKET_MODE : 0; 2703 } else { 2704 *flags = COMPILER_64_HI(rval64) & (1 << (index - 32)) ? 2705 BCM_COSQ_BW_PACKET_MODE : 0; 2706 } 2707 2708 BCM_IF_ERROR_RETURN 2709 (_bcm_td_cosq_index_resolve(unit, port, cosq, 2710 _BCM_TD_COSQ_INDEX_STYLE_BUCKET, 2711 NULL, &index, NULL)); 2712 2713 if (BCM_GPORT_IS_SCHEDULER(port)) { 2714 BCM_IF_ERROR_RETURN 2715 (_bcm_td_cosq_node_get(unit, port, NULL, NULL, NULL, &node)); 2716 if (node->level == 3) { /* S3 scheduler */ 2717 max_config_reg = S3_MAXBUCKETCONFIG_64r; 2718 min_config_reg = S3_MINBUCKETCONFIG_64r; 2719 } else if (node->level == 2) { /* S2 scheduler */ 2720 max_config_reg = S2_MAXBUCKETCONFIG_64r; 2721 min_config_reg = S2_MINBUCKETCONFIG_64r; 2722 } else { 2723 return BCM_E_PARAM; 2724 } 2725 } else if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port) || 2726 BCM_GPORT_IS_MCAST_QUEUE_GROUP(port)) { 2727 max_config_reg = MAXBUCKETCONFIG_64r; 2728 min_config_reg = MINBUCKETCONFIG_64r; 2729 } else { /* local port */ 2730 if (cosq < _BCM_TD_NUM_S3_SCHEDULER && 2731 !IS_CPU_PORT(unit, local_port)) { 2732 /* use S3.0 - S3.3 for unicast and multicast queue 0 - 3 */ 2733 max_config_reg = S3_MAXBUCKETCONFIG_64r; 2734 min_config_reg = S3_MINBUCKETCONFIG_64r; 2735 } else { /* unicast queue 4 - 7 */ 2736 max_config_reg = MAXBUCKETCONFIG_64r; 2737 min_config_reg = MINBUCKETCONFIG_64r; 2738 } 2739 } 2740 2741 meter_flags = *flags & BCM_COSQ_BW_PACKET_MODE ? 2742 _BCM_TD_METER_FLAG_PACKET_MODE : 0; 2743 BCM_IF_ERROR_RETURN(READ_MISCCONFIGr(unit, &rval)); 2744 if (soc_reg_field_get(unit, MISCCONFIGr, rval, ITU_MODE_SELf)) { 2745 meter_flags |= _BCM_TD_METER_FLAG_NON_LINEAR; 2746 } 2747 2748 BCM_IF_ERROR_RETURN(_bcm_td_cosq_refresh_freeze(unit)); 2749 rv = soc_reg_get(unit, max_config_reg, local_port, index, &rval64); 2750 BCM_IF_ERROR_RETURN(_bcm_td_cosq_refresh_thaw(unit)); 2751 if (BCM_FAILURE(rv)) { 2752 return rv; 2753 } 2754 granularity = 2755 soc_reg64_field32_get(unit, max_config_reg, rval64, METER_GRANf); 2756 refresh_rate = 2757 soc_reg64_field32_get(unit, max_config_reg, rval64, MAX_REFRESHf); 2758 bucketsize = soc_reg64_field32_get(unit, max_config_reg, rval64, MAX_THDf); 2759 BCM_IF_ERROR_RETURN 2760 (_bcm_td_bucket_encoding_to_rate(unit, refresh_rate, bucketsize, 2761 granularity, meter_flags, 2762 max_bandwidth, max_burst)); 2763 2764 BCM_IF_ERROR_RETURN(_bcm_td_cosq_refresh_freeze(unit)); 2765 rv = soc_reg_get(unit, min_config_reg, local_port, index, &rval64); 2766 BCM_IF_ERROR_RETURN(_bcm_td_cosq_refresh_thaw(unit)); 2767 if (BCM_FAILURE(rv)) { 2768 return rv; 2769 } 2770 granularity = 2771 soc_reg64_field32_get(unit, min_config_reg, rval64, METER_GRANf); 2772 refresh_rate = 2773 soc_reg64_field32_get(unit, min_config_reg, rval64, MIN_REFRESHf); 2774 bucketsize = soc_reg64_field32_get(unit, min_config_reg, rval64, MIN_THDf); 2775 BCM_IF_ERROR_RETURN 2776 (_bcm_td_bucket_encoding_to_rate(unit, refresh_rate, bucketsize, 2777 granularity, meter_flags, 2778 min_bandwidth, min_burst)); 2779 2780 return BCM_E_NONE; 2781 } 2782 2783 /* 2784 * Function: 2785 * _bcm_td_cosq_wred_set 2786 * Purpose: 2787 * Configure unicast queue WRED setting 2788 * Parameters: 2789 * unit - (IN) unit number 2790 * port - (IN) port number or GPORT identifier 2791 * cosq - (IN) COS queue number 2792 * flags - (IN) BCM_COSQ_DISCARD_XXX 2793 * min_thresh - (IN) 2794 * max_thresh - (IN) 2795 * drop_probablity - (IN) 2796 * gain - (IN) 2797 * ignore_enable_flags - (IN) 2798 * Returns: 2799 * BCM_E_XXX 2800 * Notes: 2801 * If port is any form of local port, cosq is the hardware queue index. 2802 */ 2803 STATIC int 2804 _bcm_td_cosq_wred_set(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 2805 uint32 flags, uint32 min_thresh, uint32 max_thresh, 2806 int drop_probability, int gain, int ignore_enable_flags) 2807 { 2808 soc_info_t *si; 2809 soc_reg_t reg; 2810 soc_field_t field; 2811 uint32 rval; 2812 bcm_port_t local_port; 2813 int index; 2814 uint32 profile_index, old_profile_index; 2815 mmu_wred_drop_curve_profile_0_entry_t entry_tcp_green; 2816 mmu_wred_drop_curve_profile_1_entry_t entry_tcp_yellow; 2817 mmu_wred_drop_curve_profile_2_entry_t entry_tcp_red; 2818 mmu_wred_drop_curve_profile_3_entry_t entry_nontcp_green; 2819 mmu_wred_drop_curve_profile_4_entry_t entry_nontcp_yellow; 2820 mmu_wred_drop_curve_profile_5_entry_t entry_nontcp_red; 2821 void *entries[6]; 2822 soc_mem_t mems[6]; 2823 int rate, i, exists = 0; 2824 static soc_mem_t wred_mems[6] = { 2825 MMU_WRED_DROP_CURVE_PROFILE_0m, 2826 MMU_WRED_DROP_CURVE_PROFILE_1m, 2827 MMU_WRED_DROP_CURVE_PROFILE_2m, 2828 MMU_WRED_DROP_CURVE_PROFILE_3m, 2829 MMU_WRED_DROP_CURVE_PROFILE_4m, 2830 MMU_WRED_DROP_CURVE_PROFILE_5m 2831 }; 2832 2833 if ((port == -1) && (!(flags & BCM_COSQ_DISCARD_DEVICE))) { 2834 return BCM_E_PORT; 2835 } 2836 entries[0] = &entry_tcp_green; 2837 entries[1] = &entry_tcp_yellow; 2838 entries[2] = &entry_tcp_red; 2839 entries[3] = &entry_nontcp_green; 2840 entries[4] = &entry_nontcp_yellow; 2841 entries[5] = &entry_nontcp_red; 2842 si = &SOC_INFO(unit); 2843 /* 2844 * if port == -1 and BCM_COSQ_DISCARD_DEVICE 2845 * set the all the service pools 2846 */ 2847 if ((port == -1) && (flags & BCM_COSQ_DISCARD_DEVICE)) { 2848 reg = GLOBAL_SP_WRED_CONFIGr; 2849 field = WRED_ENABLEf; 2850 local_port = 0; 2851 index = 0; 2852 } else { 2853 /* 2854 * For extended queue port: 2855 * WRED_CONFIG: 2856 * index 0: summary of regular uc cosq 0 and extended uc queue 0-15 2857 * index 1: summary of regular uc cosq 1 and extended uc queue 16-31 2858 * index 2: summary of regular uc cosq 2 and extended uc queue 32-47 2859 * index 3: summary of regular uc cosq 3 and extended uc queue 48-63 2860 * these summary does not need to equal to the sum of corresponding 2861 * entries in DMVOQ_WRED_CONFIG 2862 * DMVOQ_WRED_CONFIG: 2863 * index 0 - 63 for extended unicast queue 0 - queue 63 2864 * index 64 - 71 for unicast queue 0 - queue 7 2865 */ 2866 2867 BCM_IF_ERROR_RETURN 2868 (_bcm_td_cosq_index_resolve(unit, port, cosq, 2869 _BCM_TD_COSQ_INDEX_STYLE_WRED, 2870 &local_port, &index, NULL)); 2871 if (flags & (BCM_COSQ_DISCARD_DEVICE | BCM_COSQ_DISCARD_PORT)) { 2872 /* Get the pool number for the queue */ 2873 if (si->port_num_ext_cosq[local_port] == 0) { /* regular port */ 2874 reg = OP_UC_PORT_CONFIG1_CELLr; 2875 field = _bcm_td_uc_spid_fields[index]; 2876 } else { /* extended queue port */ 2877 reg = _bcm_td_ext_uc_spid_regs[index / 16]; 2878 field = _bcm_td_ext_uc_spid_fields[index]; 2879 } 2880 BCM_IF_ERROR_RETURN(soc_reg32_get(unit, reg, local_port, 0, &rval)); 2881 index = soc_reg_field_get(unit, reg, rval, field); 2882 2883 if (flags & BCM_COSQ_DISCARD_DEVICE) { 2884 reg = GLOBAL_SP_WRED_CONFIGr; 2885 field = WRED_ENABLEf; 2886 local_port = 0; 2887 } else { 2888 reg = PORT_SP_WRED_CONFIGr; 2889 field = WRED_ENABLEf; 2890 } 2891 } else { 2892 if (si->port_num_ext_cosq[local_port] == 0) { /* regular port */ 2893 reg = WRED_CONFIGr; 2894 } else { /* extended queue port */ 2895 reg = DMVOQ_WRED_CONFIGr; 2896 } 2897 field = WRED_ENf; 2898 } 2899 } 2900 2901 BCM_IF_ERROR_RETURN(soc_reg32_get(unit, reg, local_port, index, &rval)); 2902 2903 old_profile_index = 0xffffffff; 2904 if (flags & (BCM_COSQ_DISCARD_NONTCP | BCM_COSQ_DISCARD_COLOR_ALL | 2905 BCM_COSQ_DISCARD_TCP)) { 2906 old_profile_index = soc_reg_field_get(unit, reg, rval, PROFILE_INDEXf); 2907 BCM_IF_ERROR_RETURN 2908 (soc_profile_mem_get(unit, _bcm_td_wred_profile[unit], 2909 old_profile_index, 1, entries)); 2910 for (i = 0; i < 6; i++) { 2911 mems[i] = INVALIDm; 2912 } 2913 if (!(flags & (BCM_COSQ_DISCARD_COLOR_GREEN | 2914 BCM_COSQ_DISCARD_COLOR_YELLOW | 2915 BCM_COSQ_DISCARD_COLOR_RED))) { 2916 flags |= BCM_COSQ_DISCARD_COLOR_ALL; 2917 } 2918 if (!(flags & BCM_COSQ_DISCARD_NONTCP) || (flags & BCM_COSQ_DISCARD_TCP)) { 2919 if (flags & BCM_COSQ_DISCARD_COLOR_GREEN) { 2920 mems[0] = MMU_WRED_DROP_CURVE_PROFILE_0m; 2921 } 2922 if (flags & BCM_COSQ_DISCARD_COLOR_YELLOW) { 2923 mems[1] = MMU_WRED_DROP_CURVE_PROFILE_1m; 2924 } 2925 if (flags & BCM_COSQ_DISCARD_COLOR_RED) { 2926 mems[2] = MMU_WRED_DROP_CURVE_PROFILE_2m; 2927 } 2928 } 2929 if (flags & BCM_COSQ_DISCARD_NONTCP) { 2930 if (flags & BCM_COSQ_DISCARD_COLOR_GREEN) { 2931 mems[3] = MMU_WRED_DROP_CURVE_PROFILE_3m; 2932 } 2933 if (flags & BCM_COSQ_DISCARD_COLOR_YELLOW) { 2934 mems[4] = MMU_WRED_DROP_CURVE_PROFILE_4m; 2935 } 2936 if (flags & BCM_COSQ_DISCARD_COLOR_RED) { 2937 mems[5] = MMU_WRED_DROP_CURVE_PROFILE_5m; 2938 } 2939 } 2940 rate = _bcm_td_percent_to_drop_prob(drop_probability); 2941 for (i = 0; i < 6; i++) { 2942 exists = 0; 2943 if ((soc_mem_field32_get(unit, wred_mems[i], entries[i], 2944 MIN_THDf) != 0xffff) && 2945 (mems[i] == INVALIDm)) { 2946 mems[i] = wred_mems[i]; 2947 exists = 1; 2948 } else { 2949 soc_mem_field32_set(unit, wred_mems[i], entries[i], MIN_THDf, 2950 (mems[i] == INVALIDm) ? 0xffff : 2951 min_thresh); 2952 } 2953 2954 if ((soc_mem_field32_get(unit, wred_mems[i], entries[i], 2955 MAX_THDf) != 0xffff) && 2956 ((mems[i] == INVALIDm) || exists)) { 2957 mems[i] = wred_mems[i]; 2958 exists = 1; 2959 } else { 2960 soc_mem_field32_set(unit, wred_mems[i], entries[i], MAX_THDf, 2961 (mems[i] == INVALIDm) ? 0xffff : 2962 max_thresh); 2963 } 2964 2965 if (!exists) { 2966 soc_mem_field32_set(unit, wred_mems[i], entries[i], 2967 MAX_DROP_RATEf, 2968 (mems[i] == INVALIDm) ? 0 : rate); 2969 } 2970 } 2971 BCM_IF_ERROR_RETURN 2972 (soc_profile_mem_add(unit, _bcm_td_wred_profile[unit], entries, 1, 2973 &profile_index)); 2974 2975 soc_reg_field_set(unit, reg, &rval, PROFILE_INDEXf, profile_index); 2976 soc_reg_field_set(unit, reg, &rval, WEIGHTf, gain); 2977 } 2978 2979 /* Some APIs only modify profiles */ 2980 if (!ignore_enable_flags) { 2981 soc_reg_field_set(unit, reg, &rval, CAP_AVERAGEf, 2982 flags & BCM_COSQ_DISCARD_CAP_AVERAGE ? 1 : 0); 2983 soc_reg_field_set(unit, reg, &rval, field, 2984 flags & BCM_COSQ_DISCARD_ENABLE ? 1 : 0); 2985 if (reg == WRED_CONFIGr || reg == DMVOQ_WRED_CONFIGr) { 2986 soc_reg_field_set(unit, reg, &rval, ECN_MARKING_ENf, 2987 flags & BCM_COSQ_DISCARD_MARK_CONGESTION ? 2988 1 : 0); 2989 } 2990 } 2991 BCM_IF_ERROR_RETURN(soc_reg32_set(unit, reg, local_port, index, rval)); 2992 if ((port == -1) && (flags & BCM_COSQ_DISCARD_DEVICE)) { 2993 for (i = 1; i< 4; i++) { 2994 BCM_IF_ERROR_RETURN 2995 (soc_profile_mem_add(unit, _bcm_td_wred_profile[unit], entries, 1, 2996 &profile_index)); 2997 BCM_IF_ERROR_RETURN(soc_reg32_set(unit, reg, local_port, i, rval)); 2998 } 2999 } 3000 3001 if (old_profile_index != 0xffffffff) { 3002 BCM_IF_ERROR_RETURN 3003 (soc_profile_mem_delete(unit, _bcm_td_wred_profile[unit], 3004 old_profile_index)); 3005 if ((port == -1) &&(flags & BCM_COSQ_DISCARD_DEVICE)) { 3006 for (i = 1; i< 4; i++) { 3007 BCM_IF_ERROR_RETURN 3008 (soc_profile_mem_delete(unit, _bcm_td_wred_profile[unit], 3009 old_profile_index)); 3010 } 3011 } 3012 } 3013 3014 3015 if (!((port == -1) && (flags & BCM_COSQ_DISCARD_DEVICE))) { 3016 BCM_IF_ERROR_RETURN 3017 (_bcm_td_cosq_index_resolve(unit, port, cosq, 3018 _BCM_TD_COSQ_INDEX_STYLE_WRED_DROP_THRESH, 3019 NULL, &index, NULL)); 3020 BCM_IF_ERROR_RETURN 3021 (soc_mem_write(unit, MMU_WRED_DROP_THD_UC_ENQ0m, MEM_BLOCK_ALL, index, 3022 soc_mem_entry_null(unit, MMU_WRED_DROP_THD_UC_ENQ0m))); 3023 BCM_IF_ERROR_RETURN 3024 (soc_mem_write(unit, MMU_WRED_DROP_THD_UC_ENQ1m, MEM_BLOCK_ALL, index, 3025 soc_mem_entry_null(unit, MMU_WRED_DROP_THD_UC_ENQ1m))); 3026 BCM_IF_ERROR_RETURN 3027 (soc_mem_write(unit, MMU_WRED_DROP_THD_UC_DEQ0m, MEM_BLOCK_ALL, index, 3028 soc_mem_entry_null(unit, MMU_WRED_DROP_THD_UC_DEQ0m))); 3029 BCM_IF_ERROR_RETURN 3030 (soc_mem_write(unit, MMU_WRED_DROP_THD_UC_DEQ1m, MEM_BLOCK_ALL, index, 3031 soc_mem_entry_null(unit, MMU_WRED_DROP_THD_UC_DEQ1m))); 3032 } 3033 return BCM_E_NONE; 3034 } 3035 3036 /* 3037 * Function: 3038 * _bcm_td_cosq_wred_get 3039 * Purpose: 3040 * Get unicast queue WRED setting 3041 * Parameters: 3042 * unit - (IN) unit number 3043 * port - (IN) port number or GPORT identifier 3044 * cosq - (IN) COS queue number 3045 * flags - (IN/OUT) BCM_COSQ_DISCARD_XXX 3046 * min_thresh - (OUT) 3047 * max_thresh - (OUT) 3048 * drop_probablity - (OUT) 3049 * gain - (OUT) 3050 * Returns: 3051 * BCM_E_XXX 3052 * Notes: 3053 * If port is any form of local port, cosq is the hardware queue index. 3054 */ 3055 STATIC int 3056 _bcm_td_cosq_wred_get(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 3057 uint32 *flags, uint32 *min_thresh, uint32 *max_thresh, 3058 int *drop_probability, int *gain) 3059 { 3060 soc_info_t *si; 3061 soc_reg_t reg; 3062 soc_field_t field; 3063 uint32 rval; 3064 bcm_port_t local_port; 3065 int index, profile_index; 3066 mmu_wred_drop_curve_profile_0_entry_t entry_tcp_green; 3067 mmu_wred_drop_curve_profile_1_entry_t entry_tcp_yellow; 3068 mmu_wred_drop_curve_profile_2_entry_t entry_tcp_red; 3069 mmu_wred_drop_curve_profile_3_entry_t entry_nontcp_green; 3070 mmu_wred_drop_curve_profile_4_entry_t entry_nontcp_yellow; 3071 mmu_wred_drop_curve_profile_5_entry_t entry_nontcp_red; 3072 void *entries[6]; 3073 void *entry_p; 3074 soc_mem_t mem; 3075 int rate; 3076 if ((port == -1) && (!(*flags & BCM_COSQ_DISCARD_DEVICE))) { 3077 return BCM_E_PORT; 3078 } 3079 3080 si = &SOC_INFO(unit); 3081 if ((port == -1 ) && (*flags & BCM_COSQ_DISCARD_DEVICE)) { 3082 reg = GLOBAL_SP_WRED_CONFIGr; 3083 field = WRED_ENABLEf; 3084 local_port = 0; 3085 index = 0; 3086 } else { 3087 BCM_IF_ERROR_RETURN 3088 (_bcm_td_cosq_index_resolve(unit, port, cosq, 3089 _BCM_TD_COSQ_INDEX_STYLE_WRED, 3090 &local_port, &index, NULL)); 3091 if (*flags & (BCM_COSQ_DISCARD_DEVICE | BCM_COSQ_DISCARD_PORT)) { 3092 /* Get the pool number for the queue */ 3093 if (si->port_num_ext_cosq[local_port] == 0) { /* regular port */ 3094 reg = OP_UC_PORT_CONFIG1_CELLr; 3095 field = _bcm_td_uc_spid_fields[index]; 3096 } else { /* extended queue port */ 3097 reg = _bcm_td_ext_uc_spid_regs[index / 16]; 3098 field = _bcm_td_ext_uc_spid_fields[index]; 3099 } 3100 BCM_IF_ERROR_RETURN(soc_reg32_get(unit, reg, local_port, 0, &rval)); 3101 index = soc_reg_field_get(unit, reg, rval, field); 3102 if (*flags & BCM_COSQ_DISCARD_DEVICE) { 3103 reg = GLOBAL_SP_WRED_CONFIGr; 3104 field = WRED_ENABLEf; 3105 local_port = 0; 3106 } else { 3107 reg = PORT_SP_WRED_CONFIGr; 3108 field = WRED_ENABLEf; 3109 } 3110 } else { 3111 if (si->port_num_ext_cosq[local_port] == 0) { /* regular port */ 3112 reg = WRED_CONFIGr; 3113 } else { /* extended queue port */ 3114 reg = DMVOQ_WRED_CONFIGr; 3115 } 3116 field = WRED_ENf; 3117 } 3118 } 3119 3120 BCM_IF_ERROR_RETURN(soc_reg32_get(unit, reg, local_port, index, &rval)); 3121 3122 if (!(*flags & BCM_COSQ_DISCARD_NONTCP)) { 3123 if (*flags & BCM_COSQ_DISCARD_COLOR_GREEN) { 3124 mem = MMU_WRED_DROP_CURVE_PROFILE_0m; 3125 entry_p = &entry_tcp_green; 3126 } else if (*flags & BCM_COSQ_DISCARD_COLOR_YELLOW) { 3127 mem = MMU_WRED_DROP_CURVE_PROFILE_1m; 3128 entry_p = &entry_tcp_yellow; 3129 } else if (*flags & BCM_COSQ_DISCARD_COLOR_RED) { 3130 mem = MMU_WRED_DROP_CURVE_PROFILE_2m; 3131 entry_p = &entry_tcp_red; 3132 } else { 3133 mem = MMU_WRED_DROP_CURVE_PROFILE_0m; 3134 entry_p = &entry_tcp_green; 3135 } 3136 } else { 3137 if (*flags & BCM_COSQ_DISCARD_COLOR_GREEN) { 3138 mem = MMU_WRED_DROP_CURVE_PROFILE_3m; 3139 entry_p = &entry_nontcp_green; 3140 } else if (*flags & BCM_COSQ_DISCARD_COLOR_YELLOW) { 3141 mem = MMU_WRED_DROP_CURVE_PROFILE_4m; 3142 entry_p = &entry_nontcp_yellow; 3143 } else if (*flags & BCM_COSQ_DISCARD_COLOR_RED) { 3144 mem = MMU_WRED_DROP_CURVE_PROFILE_5m; 3145 entry_p = &entry_nontcp_red; 3146 } else { 3147 mem = MMU_WRED_DROP_CURVE_PROFILE_3m; 3148 entry_p = &entry_nontcp_green; 3149 } 3150 } 3151 profile_index = soc_reg_field_get(unit, reg, rval, PROFILE_INDEXf); 3152 entries[0] = &entry_tcp_green; 3153 entries[1] = &entry_tcp_yellow; 3154 entries[2] = &entry_tcp_red; 3155 entries[3] = &entry_nontcp_green; 3156 entries[4] = &entry_nontcp_yellow; 3157 entries[5] = &entry_nontcp_red; 3158 BCM_IF_ERROR_RETURN 3159 (soc_profile_mem_get(unit, _bcm_td_wred_profile[unit], 3160 profile_index, 1, entries)); 3161 if (min_thresh != NULL) { 3162 *min_thresh = soc_mem_field32_get(unit, mem, entry_p, MIN_THDf); 3163 } 3164 if (max_thresh != NULL) { 3165 *max_thresh = soc_mem_field32_get(unit, mem, entry_p, MAX_THDf); 3166 } 3167 if (drop_probability != NULL) { 3168 rate = soc_mem_field32_get(unit, mem, entry_p, MAX_DROP_RATEf); 3169 *drop_probability = _bcm_td_drop_prob_to_percent(rate); 3170 } 3171 3172 if (gain != NULL) { 3173 *gain = soc_reg_field_get(unit, reg, rval, WEIGHTf); 3174 } 3175 3176 *flags &= ~(BCM_COSQ_DISCARD_CAP_AVERAGE | BCM_COSQ_DISCARD_ENABLE); 3177 if (soc_reg_field_get(unit, reg, rval, CAP_AVERAGEf)) { 3178 *flags |= BCM_COSQ_DISCARD_CAP_AVERAGE; 3179 } 3180 if (soc_reg_field_get(unit, reg, rval, field)) { 3181 *flags |= BCM_COSQ_DISCARD_ENABLE; 3182 } 3183 if (reg == WRED_CONFIGr || reg == DMVOQ_WRED_CONFIGr) { 3184 if (soc_reg_field_get(unit, reg, rval, ECN_MARKING_ENf)) { 3185 *flags |= BCM_COSQ_DISCARD_MARK_CONGESTION; 3186 } 3187 } 3188 3189 return BCM_E_NONE; 3190 } 3191 3192 /* 3193 * Function: 3194 * _bcm_td_cosq_sched_set 3195 * Purpose: 3196 * Set scheduling mode 3197 * Parameters: 3198 * unit - (IN) unit number 3199 * port - (IN) port number or GPORT identifier 3200 * cosq - (IN) COS queue number 3201 * mode - (IN) scheduling mode (BCM_COSQ_XXX) 3202 * num_weights - (IN) number of entries in weights array 3203 * weights - (IN) weights array 3204 * Returns: 3205 * BCM_E_XXX 3206 */ 3207 STATIC int 3208 _bcm_td_cosq_sched_set(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 3209 int mode, int num_weights, int *weights) 3210 { 3211 soc_info_t *si; 3212 _bcm_td_cosq_port_info_t *port_info; 3213 _bcm_td_cosq_node_t *node; 3214 bcm_port_t local_port; 3215 int index, minsp_index; 3216 soc_reg_t config_reg, weight_reg, minsp_reg; 3217 uint32 rval, fval, rval_hi, rval_lo; 3218 uint64 rval64; 3219 int mode_sel_shift, max_weight, minsp_width, mode_sel, i; 3220 3221 if (cosq < 0) { 3222 if (cosq == -1) { 3223 /* caller needs to resolve the wild card value (-1) */ 3224 return BCM_E_INTERNAL; 3225 } else { /* reject all other negative value */ 3226 return BCM_E_PARAM; 3227 } 3228 } 3229 3230 si = &SOC_INFO(unit); 3231 3232 mode_sel_shift = 0; 3233 minsp_index = 0; 3234 minsp_width = -1; 3235 3236 if (BCM_GPORT_IS_SCHEDULER(port)) { /* ETS style scheduler */ 3237 BCM_IF_ERROR_RETURN 3238 (_bcm_td_cosq_node_get(unit, port, NULL, &local_port, NULL, 3239 &node)); 3240 3241 if (cosq + num_weights > node->numq) { 3242 return BCM_E_PARAM; 3243 } 3244 3245 if (node->hw_cosq_attached_to < 0) { /* Not resolved yet */ 3246 return BCM_E_NOT_FOUND; 3247 } 3248 3249 switch (node->level) { 3250 case 1: /* S1 scheduler */ 3251 config_reg = ESCONFIGr; 3252 weight_reg = COSWEIGHTSr; 3253 minsp_reg = MINSPCONFIGr; 3254 break; 3255 case 2: 3256 if (node->hw_cosq_attached_to == 0) { /* MC group scheduler */ 3257 config_reg = S3_CONFIG_MCr; 3258 weight_reg = S3_COSWEIGHTSr; 3259 minsp_reg = S3_MINSPCONFIG_MCr; 3260 } else { /* S2 scheduler */ 3261 config_reg = S2_CONFIGr; 3262 weight_reg = S2_COSWEIGHTSr; 3263 minsp_reg = S2_MINSPCONFIGr; 3264 mode_sel_shift = (node->hw_cosq_attached_to - 1) * 2; 3265 } 3266 break; 3267 case 3: /* S3 scheduler */ 3268 config_reg = S3_CONFIGr; 3269 weight_reg = S3_COSWEIGHTSr; 3270 minsp_reg = S3_MINSPCONFIGr; 3271 mode_sel_shift = node->hw_cosq_attached_to * 2; 3272 minsp_index = node->hw_cosq_attached_to; 3273 minsp_width = si->port_num_ext_cosq[local_port] ? 18 : 2; 3274 break; 3275 default: 3276 return BCM_E_INTERNAL; 3277 } 3278 } else { /* non-ETS style scheduler */ 3279 BCM_IF_ERROR_RETURN 3280 (_bcm_td_cosq_localport_resolve(unit, port, &local_port)); 3281 if (IS_CPU_PORT(unit, local_port)) { 3282 if (cosq + num_weights > si->num_cpu_cosq) { 3283 return BCM_E_PARAM; 3284 } 3285 config_reg = ESCONFIGr; 3286 weight_reg = COSWEIGHTSr; 3287 minsp_reg = MINSPCONFIG_CPUr; 3288 } else { 3289 port_info = &_bcm_td_cosq_port_info[unit][local_port]; 3290 for (i = 0; i < _BCM_TD_NUM_SCHEDULER; i++) { 3291 if (port_info->sched[i].numq > 0 && 3292 port_info->sched[i].cosq_attached_to != -1) { 3293 /* ETS style scheduling has been setup */ 3294 return BCM_E_PORT; 3295 } 3296 } 3297 if (cosq + num_weights > _BCM_TD_NUM_NON_SC_QM_UCAST_QUEUE) { 3298 return BCM_E_PARAM; 3299 } 3300 config_reg = S2_CONFIGr; 3301 weight_reg = S2_COSWEIGHTSr; 3302 minsp_reg = S2_MINSPCONFIGr; 3303 mode_sel_shift = 0; /* S2.0 */ 3304 } 3305 } 3306 3307 switch (mode) { 3308 case BCM_COSQ_STRICT: 3309 mode_sel = 0; 3310 break; 3311 case BCM_COSQ_ROUND_ROBIN: 3312 mode_sel = 1; 3313 break; 3314 case BCM_COSQ_WEIGHTED_ROUND_ROBIN: 3315 mode_sel = 2; 3316 break; 3317 case BCM_COSQ_DEFICIT_ROUND_ROBIN: 3318 mode_sel = 3; 3319 break; 3320 default: 3321 return BCM_E_PARAM; 3322 } 3323 3324 if (mode == BCM_COSQ_WEIGHTED_ROUND_ROBIN || 3325 mode == BCM_COSQ_DEFICIT_ROUND_ROBIN) { 3326 max_weight = 3327 (1 << soc_reg_field_length(unit, weight_reg, COSWEIGHTSf)) - 1; 3328 for (i = 0; i < num_weights; i++) { 3329 if (weights[i] < 0 || weights[i] > max_weight) { 3330 return BCM_E_PARAM; 3331 } 3332 } 3333 3334 BCM_IF_ERROR_RETURN 3335 (soc_reg_get(unit, minsp_reg, local_port, minsp_index, &rval64)); 3336 rval_hi = COMPILER_64_HI(rval64); 3337 rval_lo = COMPILER_64_LO(rval64); 3338 for (i = 0; i < num_weights; i++) { 3339 BCM_IF_ERROR_RETURN 3340 (_bcm_td_cosq_index_resolve(unit, port, cosq + i, 3341 _BCM_TD_COSQ_INDEX_STYLE_SCHEDULER, 3342 NULL, &index, NULL)); 3343 BCM_IF_ERROR_RETURN 3344 (soc_reg32_get(unit, weight_reg, local_port, index, &rval)); 3345 soc_reg_field_set(unit, weight_reg, &rval, COSWEIGHTSf, 3346 weights[i]); 3347 BCM_IF_ERROR_RETURN 3348 (soc_reg32_set(unit, weight_reg, local_port, index, rval)); 3349 3350 /* Set strict priority bit if weight is zero */ 3351 if (minsp_width != -1) { 3352 index %= minsp_width; 3353 } 3354 if (index < 32) { 3355 if (weights[i] != 0) { 3356 rval_lo &= ~(1 << index); 3357 } else { 3358 rval_lo |= 1 << index; 3359 } 3360 } else { 3361 if (weights[i] != 0) { 3362 rval_hi &= ~(1 << (index - 32)); 3363 } else { 3364 rval_hi |= 1 << (index - 32); 3365 } 3366 } 3367 } 3368 3369 COMPILER_64_SET(rval64, rval_hi, rval_lo); 3370 BCM_IF_ERROR_RETURN 3371 (soc_reg_set(unit, minsp_reg, local_port, 0, rval64)); 3372 } 3373 3374 /* Program the scheduling mode */ 3375 BCM_IF_ERROR_RETURN(soc_reg32_get(unit, config_reg, local_port, 0, &rval)); 3376 fval = soc_reg_field_get(unit, config_reg, rval, SCHEDULING_SELECTf); 3377 fval &= ~(0x3 << mode_sel_shift); 3378 fval |= mode_sel << mode_sel_shift; 3379 soc_reg_field_set(unit, config_reg, &rval, SCHEDULING_SELECTf, fval); 3380 BCM_IF_ERROR_RETURN(soc_reg32_set(unit, config_reg, local_port, 0, rval)); 3381 3382 return BCM_E_NONE; 3383 } 3384 3385 /* 3386 * Function: 3387 * _bcm_td_cosq_sched_get 3388 * Purpose: 3389 * Get scheduling mode setting 3390 * Parameters: 3391 * unit - (IN) unit number 3392 * port - (IN) port number or GPORT identifier 3393 * cosq - (IN) COS queue number 3394 * mode - (OUT) scheduling mode (BCM_COSQ_XXX) 3395 * num_weights - (IN) number of entries in weights array 3396 * weights - (OUT) weights array 3397 * Returns: 3398 * BCM_E_XXX 3399 */ 3400 STATIC int 3401 _bcm_td_cosq_sched_get(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 3402 int *mode, int num_weights, int *weights) 3403 { 3404 soc_info_t *si; 3405 _bcm_td_cosq_port_info_t *port_info; 3406 _bcm_td_cosq_node_t *node; 3407 bcm_port_t local_port; 3408 int index; 3409 soc_reg_t config_reg, weight_reg; 3410 uint32 rval; 3411 int mode_sel_shift, mode_sel, i; 3412 3413 if (cosq < 0) { 3414 if (cosq == -1) { 3415 /* caller needs to resolve the wild card value (-1) */ 3416 return BCM_E_INTERNAL; 3417 } else { /* reject all other negative value */ 3418 return BCM_E_PARAM; 3419 } 3420 } 3421 3422 si = &SOC_INFO(unit); 3423 3424 mode_sel_shift = 0; 3425 3426 if (BCM_GPORT_IS_SCHEDULER(port)) { /* ETS style scheduler */ 3427 BCM_IF_ERROR_RETURN 3428 (_bcm_td_cosq_node_get(unit, port, NULL, &local_port, NULL, 3429 &node)); 3430 3431 if (cosq + num_weights > node->numq) { 3432 return BCM_E_PARAM; 3433 } 3434 3435 if (node->hw_cosq_attached_to < 0) { /* Not resolved yet */ 3436 return BCM_E_NOT_FOUND; 3437 } 3438 3439 switch (node->level) { 3440 case 1: /* S1 scheduler */ 3441 config_reg = ESCONFIGr; 3442 weight_reg = COSWEIGHTSr; 3443 break; 3444 case 2: 3445 if (node->hw_cosq_attached_to == 0) { /* MC group scheduler */ 3446 config_reg = S3_CONFIG_MCr; 3447 weight_reg = S3_COSWEIGHTSr; 3448 } else { /* S2 scheduler */ 3449 config_reg = S2_CONFIGr; 3450 weight_reg = S2_COSWEIGHTSr; 3451 mode_sel_shift = (node->hw_cosq_attached_to - 1) * 2; 3452 } 3453 break; 3454 case 3: /* S3 scheduler */ 3455 config_reg = S3_CONFIGr; 3456 weight_reg = S3_COSWEIGHTSr; 3457 mode_sel_shift = node->hw_cosq_attached_to * 2; 3458 break; 3459 default: 3460 return BCM_E_INTERNAL; 3461 } 3462 } else { /* non-ETS style scheduler */ 3463 BCM_IF_ERROR_RETURN 3464 (_bcm_td_cosq_localport_resolve(unit, port, &local_port)); 3465 if (IS_CPU_PORT(unit, local_port)) { 3466 if (cosq + num_weights > si->num_cpu_cosq) { 3467 return BCM_E_PARAM; 3468 } 3469 config_reg = ESCONFIGr; 3470 weight_reg = COSWEIGHTSr; 3471 } else { 3472 port_info = &_bcm_td_cosq_port_info[unit][local_port]; 3473 for (i = 0; i < _BCM_TD_NUM_SCHEDULER; i++) { 3474 if (port_info->sched[i].numq > 0 && 3475 port_info->sched[i].cosq_attached_to != -1) { 3476 /* ETS style scheduling has been setup */ 3477 return BCM_E_PORT; 3478 } 3479 } 3480 if (cosq + num_weights > _BCM_TD_NUM_NON_SC_QM_UCAST_QUEUE) { 3481 return BCM_E_PARAM; 3482 } 3483 config_reg = S2_CONFIGr; 3484 weight_reg = S2_COSWEIGHTSr; 3485 mode_sel_shift = 0; /* S2.0 */ 3486 } 3487 } 3488 3489 BCM_IF_ERROR_RETURN(soc_reg32_get(unit, config_reg, local_port, 0, &rval)); 3490 mode_sel = soc_reg_field_get(unit, config_reg, rval, SCHEDULING_SELECTf); 3491 3492 switch ((mode_sel >> mode_sel_shift) & 0x03) { 3493 case 0: 3494 *mode = BCM_COSQ_STRICT; 3495 break; 3496 case 1: 3497 *mode = BCM_COSQ_ROUND_ROBIN; 3498 break; 3499 case 2: 3500 *mode = BCM_COSQ_WEIGHTED_ROUND_ROBIN; 3501 break; 3502 case 3: 3503 *mode = BCM_COSQ_DEFICIT_ROUND_ROBIN; 3504 break; 3505 } 3506 3507 if (*mode == BCM_COSQ_WEIGHTED_ROUND_ROBIN || 3508 *mode == BCM_COSQ_DEFICIT_ROUND_ROBIN) { 3509 for (i = 0; i < num_weights; i++) { 3510 BCM_IF_ERROR_RETURN 3511 (_bcm_td_cosq_index_resolve(unit, port, cosq + i, 3512 _BCM_TD_COSQ_INDEX_STYLE_SCHEDULER, 3513 NULL, &index, NULL)); 3514 BCM_IF_ERROR_RETURN(soc_reg32_get(unit, weight_reg, local_port, 3515 index, &rval)); 3516 weights[i] = soc_reg_field_get(unit, weight_reg, rval, 3517 COSWEIGHTSf); 3518 } 3519 } 3520 3521 return BCM_E_NONE; 3522 } 3523 3524 STATIC int 3525 _bcm_td_cosq_ingress_sp_get(int unit, bcm_gport_t gport, 3526 bcm_cos_queue_t pri_grp, int *p_pool_start, 3527 int *p_pool_end) 3528 { 3529 int local_port; 3530 uint32 rval, pool; 3531 static const soc_field_t prigroup_spid_field[] = { 3532 PG0_SPIDf, PG1_SPIDf, PG2_SPIDf, PG3_SPIDf, 3533 PG4_SPIDf, PG5_SPIDf, PG6_SPIDf, PG7_SPIDf 3534 }; 3535 3536 if (pri_grp == BCM_COS_INVALID) { 3537 *p_pool_start = 0; 3538 *p_pool_end = 3; 3539 return BCM_E_NONE; 3540 } 3541 3542 BCM_IF_ERROR_RETURN 3543 (_bcm_td_cosq_localport_resolve(unit, gport, &local_port)); 3544 3545 if (!SOC_PORT_VALID(unit, local_port)) { 3546 return BCM_E_PORT; 3547 } 3548 3549 if (pri_grp >= 8) { 3550 return BCM_E_PARAM; 3551 } 3552 3553 SOC_IF_ERROR_RETURN(READ_PORT_PG_SPIDr(unit, local_port, &rval)); 3554 pool = soc_reg_field_get(unit, PORT_PG_SPIDr, rval, 3555 prigroup_spid_field[pri_grp]); 3556 3557 *p_pool_start = *p_pool_end = pool; 3558 return BCM_E_NONE; 3559 } 3560 3561 #ifdef BCM_WARM_BOOT_SUPPORT 3562 3563 #define BCM_WB_VERSION_1_0 SOC_SCACHE_VERSION(1,0) 3564 #define BCM_WB_VERSION_1_1 SOC_SCACHE_VERSION(1,1) 3565 #define BCM_WB_DEFAULT_VERSION BCM_WB_VERSION_1_1 3566 3567 #define _BCM_TD_COSQ_WB_UCAST_COSQ_MASK 0x1f /* byte 0 bit 4-0 */ 3568 #define _BCM_TD_COSQ_WB_UCAST_COSQ_SHIFT 0 3569 #define _BCM_TD_COSQ_WB_UCAST_BASE_MASK 0x07 /* byte 0 bit 7-5 */ 3570 #define _BCM_TD_COSQ_WB_UCAST_BASE_SHIFT 5 3571 #define _BCM_TD_COSQ_WB_MCAST_COSQ_MASK 0x1f /* byte 0 bit 4-0 */ 3572 #define _BCM_TD_COSQ_WB_MCAST_COSQ_SHIFT 0 3573 #define _BCM_TD_COSQ_WB_MCAST_BASE_MASK 0x07 /* byte 0 bit 7-5 */ 3574 #define _BCM_TD_COSQ_WB_MCAST_BASE_SHIFT 5 3575 #define _BCM_TD_COSQ_WB_EXT_UCAST_COSQ_MASK 0x1f /* byte 0 bit 4-0 */ 3576 #define _BCM_TD_COSQ_WB_EXT_UCAST_COSQ_SHIFT 0 3577 #define _BCM_TD_COSQ_WB_EXT_UCAST_NUMQ_MASK 0x07 /* byte 0 bit 7-5 */ 3578 #define _BCM_TD_COSQ_WB_EXT_UCAST_NUMQ_SHIFT 5 3579 #define _BCM_TD_COSQ_WB_EXT_UCAST_BASE_MASK 0x0f /* byte 1 bit 3-0 */ 3580 #define _BCM_TD_COSQ_WB_EXT_UCAST_BASE_SHIFT 0 3581 #define _BCM_TD_COSQ_WB_SCHED_LEVEL_MASK 0x03 /* byte 0 bit 1-0 */ 3582 #define _BCM_TD_COSQ_WB_SCHED_LEVEL_SHIFT 0 3583 #define _BCM_TD_COSQ_WB_SCHED_NUMQ_MASK 0x1f /* byte 0 bit 6-2 */ 3584 #define _BCM_TD_COSQ_WB_SCHED_NUMQ_SHIFT 2 3585 #define _BCM_TD_COSQ_WB_SCHED_COSQ_MASK 0x0f /* byte 1 bit 3-0 */ 3586 #define _BCM_TD_COSQ_WB_SCHED_COSQ_SHIFT 0 3587 #define _BCM_TD_COSQ_WB_SCHED_HW_COSQ_MASK 0x07 /* byte 1 bit 6-4 */ 3588 #define _BCM_TD_COSQ_WB_SCHED_HW_COSQ_SHIFT 4 3589 3590 #define SET_FIELD(_field, _value) \ 3591 (((_value) & _BCM_TD_COSQ_WB_## _field## _MASK) << \ 3592 _BCM_TD_COSQ_WB_## _field## _SHIFT) 3593 #define GET_FIELD(_field, _byte) \ 3594 (((_byte) >> _BCM_TD_COSQ_WB_## _field## _SHIFT) & \ 3595 _BCM_TD_COSQ_WB_## _field## _MASK) 3596 3597 /* 3598 * Function: 3599 * _bcm_td_cosq_wb_alloc_size_get 3600 * Purpose: 3601 * Calculates the scache space required for a given warmboot version 3602 * Parameters: 3603 * unit - unit number 3604 * wb_ver - WarmBoot version 3605 * Returns: 3606 * Size of scache size required 3607 * Notes: 3608 * Handle scache allocation sizes for new versions 3609 */ 3610 STATIC int 3611 _bcm_td_cosq_wb_alloc_size_get(int unit, int wb_ver) 3612 { 3613 bcm_port_t port; 3614 int alloc_size = 0; 3615 3616 PBMP_ALL_ITER(unit, port) { 3617 if (IS_CPU_PORT(unit, port)) { 3618 continue; 3619 } 3620 if (SOC_INFO(unit).port_num_ext_cosq[port] != 0) { 3621 alloc_size += 68; 3622 } else { 3623 alloc_size += 36; 3624 } 3625 /* Scache space to save ucast SC/QM queu info */ 3626 if (wb_ver >= BCM_WB_VERSION_1_1) { 3627 alloc_size += 3; 3628 } 3629 } 3630 3631 return alloc_size; 3632 } 3633 3634 /* 3635 * Function: 3636 * _bcm_td_cosq_wb_alloc 3637 * Purpose: 3638 * Allocates required scache space in Cold Boot 3639 * Parameters: 3640 * unit - unit number 3641 * Returns: 3642 * BCM_E_XXX 3643 */ 3644 STATIC int 3645 _bcm_td_cosq_wb_alloc(int unit) 3646 { 3647 soc_scache_handle_t scache_handle; 3648 uint8 *scache_ptr; 3649 int rv, alloc_size; 3650 3651 alloc_size = _bcm_td_cosq_wb_alloc_size_get(unit, BCM_WB_DEFAULT_VERSION); 3652 3653 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 0); 3654 /* Allocate required scache size */ 3655 rv = _bcm_esw_scache_ptr_get(unit, scache_handle, TRUE, alloc_size, 3656 &scache_ptr, BCM_WB_DEFAULT_VERSION, NULL); 3657 if (rv == BCM_E_NOT_FOUND) { 3658 rv = BCM_E_NONE; 3659 } 3660 3661 return rv; 3662 } 3663 3664 int 3665 bcm_td_cosq_sync(int unit) 3666 { 3667 soc_scache_handle_t scache_handle; 3668 uint8 *scache_ptr, *map; 3669 uint8 *scache_ptr_2, *map_2; 3670 _bcm_td_cosq_port_info_t *port_info; 3671 _bcm_td_cosq_node_t *node; 3672 bcm_port_t port; 3673 int index; 3674 uint32 num_cosq; 3675 3676 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 0); 3677 BCM_IF_ERROR_RETURN 3678 (_bcm_esw_scache_ptr_get(unit, scache_handle, FALSE, 0, 3679 &scache_ptr, BCM_WB_DEFAULT_VERSION, NULL)); 3680 3681 /* WB version 1.1 state starts at the end of scache for 1.0 version */ 3682 scache_ptr_2 = scache_ptr + 3683 _bcm_td_cosq_wb_alloc_size_get(unit, BCM_WB_VERSION_1_0); 3684 3685 PBMP_ALL_ITER(unit, port) { 3686 if (IS_CPU_PORT(unit, port)) { 3687 continue; 3688 } 3689 port_info = &_bcm_td_cosq_port_info[unit][port]; 3690 3691 /* Store unicast queue info into scache */ 3692 map = scache_ptr; 3693 *map = 0; 3694 scache_ptr++; 3695 for (index = 0; index < _BCM_TD_NUM_NON_SC_QM_UCAST_QUEUE; index++) { 3696 node = &port_info->ucast[index]; 3697 if (node->numq == 0) { 3698 continue; 3699 } 3700 /* 3701 * value range: 3702 * numq: 1, or 0 for unused entry 3703 * base: 0 - 7 3704 * cosq_attached_to: -1 for unattached node 3705 * 0 - 1 on regular port 3706 * 0 - 17 on extended queue port 3707 */ 3708 *map |= 1 << index; 3709 *scache_ptr = SET_FIELD(UCAST_COSQ, node->cosq_attached_to) | 3710 SET_FIELD(UCAST_BASE, node->base); 3711 scache_ptr++; 3712 } 3713 3714 /* Store unicast SC/QM queue info into scache */ 3715 /* Note that scache_ptr_2 is used to recovered for level 1.2 */ 3716 map_2 = scache_ptr_2; 3717 *map_2 = 0; 3718 scache_ptr_2++; 3719 for (index = _BCM_TD_NUM_NON_SC_QM_UCAST_QUEUE; 3720 index < _BCM_TD_NUM_UCAST_QUEUE_GROUP; 3721 index++) { 3722 node = &port_info->ucast[index]; 3723 if (node->numq == 0) { 3724 continue; 3725 } 3726 /* 3727 * value range for SC or QM queue (special encoding): 3728 * numq: 1, or 0 for unused entry 3729 * base : 8 - 9 3730 * cosq_attached_to: -1 for unattched node 3731 * 0 - 6 3732 * use magic number (base + 10) in UCAST_COSQ 3733 * use cosq_attached_to in UCAST_BASE 3734 */ 3735 *map_2 |= 1 << (index - _BCM_TD_NUM_NON_SC_QM_UCAST_QUEUE); 3736 *scache_ptr_2 = SET_FIELD(UCAST_COSQ, node->base + 10) | 3737 SET_FIELD(UCAST_BASE, node->cosq_attached_to); 3738 scache_ptr_2++; 3739 } 3740 3741 /* Store multicast queue info into scache */ 3742 map = scache_ptr; 3743 *map = 0; 3744 scache_ptr++; 3745 for (index = 0; index < _BCM_TD_NUM_MCAST_QUEUE_GROUP; index++) { 3746 node = &port_info->mcast[index]; 3747 if (node->numq == 0) { 3748 continue; 3749 } 3750 /* 3751 * value range: 3752 * numq: 1, or 0 for unused entry 3753 * base: 0 - 3 3754 * cosq_attached_to: -1 for unattached node 3755 * 0 - 1 on regular port 3756 * 0 - 17 on extended queue port 3757 * value range for SC/QM queue: 3758 * numq: 1, or 0 for unused entry 3759 * base: 4 3760 * cosq_attached_to: -1 for unattached node 3761 * 0 - 6 3762 */ 3763 *map |= 1 << index; 3764 *scache_ptr = SET_FIELD(MCAST_COSQ, node->cosq_attached_to) | 3765 SET_FIELD(MCAST_BASE, node->base); 3766 scache_ptr++; 3767 } 3768 3769 /* Store extended unicast queue info into scache */ 3770 if (SOC_INFO(unit).port_num_ext_cosq[port] != 0) { 3771 map = scache_ptr; 3772 *map = 0; 3773 scache_ptr += 2; 3774 for (index = 0; index < _BCM_TD_NUM_EXT_UCAST_QUEUE_GROUP; 3775 index++) { 3776 node = &port_info->ext_ucast[index]; 3777 if (node->numq == 0) { 3778 continue; 3779 } 3780 /* 3781 * value range: 3782 * numq: 1 - 4, or 0 for unused entry 3783 * base: 0 - 15 3784 * cosq_attached_to: 0 - 17, or -1 for unattached node 3785 */ 3786 map[index >> 3] |= 1 << (index & 0x07); 3787 *scache_ptr = 3788 SET_FIELD(EXT_UCAST_COSQ, node->cosq_attached_to) | 3789 SET_FIELD(EXT_UCAST_NUMQ, node->numq); 3790 scache_ptr++; 3791 if (node->cosq_attached_to != -1) { 3792 *scache_ptr = SET_FIELD(EXT_UCAST_BASE, node->base); 3793 scache_ptr++; 3794 } 3795 } 3796 } 3797 3798 /* Store scheduler info into scache */ 3799 map = scache_ptr; 3800 *map = 0; 3801 scache_ptr += 2; 3802 for (index = 0; index < _BCM_TD_NUM_SCHEDULER; index++) { 3803 node = &port_info->sched[index]; 3804 if (node->numq == 0) { 3805 continue; 3806 } 3807 /* 3808 * value range: 3809 * numq: 0 for unused entry 3810 * 1 - 4 for S1 scheduler 3811 * 1 - 4 for MC group scheduler 3812 * 1 - 9 for S2 scheduler 3813 * 1 - 18 for S3 scheduler 3814 * cosq_attached_to: -1 for unattached node 3815 * 0 for S1 scheduler 3816 * 0 - 3 for MC group and S3 scheduler 3817 * 0 - 8 for S3 scheduler 3818 * hw_cosq_attached_to: -1 for unattached or unresolved node 3819 * 0 for S1 and MC group scheduler 3820 * 1 - 3 for S2 scheduler 3821 * 0 - 3 for S3 scheduler 3822 * level: 1 - 3, or 0 for unattached node 3823 */ 3824 map[index >> 3] |= 1 << (index & 0x07); 3825 *scache_ptr = SET_FIELD(SCHED_LEVEL, node->level) | 3826 SET_FIELD(SCHED_NUMQ, node->numq); 3827 scache_ptr++; 3828 if (node->level != 0) { 3829 *scache_ptr = SET_FIELD(SCHED_COSQ, node->cosq_attached_to) | 3830 SET_FIELD(SCHED_HW_COSQ, node->hw_cosq_attached_to); 3831 scache_ptr++; 3832 } 3833 } 3834 } 3835 /* Number COSQ */ 3836 num_cosq = _bcm_td_num_cosq[unit]; 3837 sal_memcpy(scache_ptr_2, &num_cosq, sizeof(num_cosq)); 3838 3839 return BCM_E_NONE; 3840 } 3841 3842 int 3843 bcm_td_cosq_reinit(int unit) 3844 { 3845 soc_scache_handle_t scache_handle; 3846 uint8 *scache_ptr, *map, value; 3847 uint8 *scache_ptr_2, *map_2; 3848 uint16 recovered_ver; 3849 int additional_scache_size = 0; 3850 soc_info_t *si; 3851 _bcm_td_cosq_port_info_t *port_info; 3852 _bcm_td_cosq_node_t *node, *s1_node, *s2_node[3], *s3_node[4], *mcg_node; 3853 bcm_module_t local_modid, modid_out; 3854 bcm_port_t port, port_out, phy_port, mmu_port; 3855 uint64 rval64; 3856 uint32 addr, rval, s2_input[3], sched_encap; 3857 int rv, uc_to_s2, use_mc_group, index, s2_index, hw_cosq, stable_size = 0; 3858 soc_profile_mem_t *profile_mem; 3859 soc_profile_reg_t *profile_reg0, *profile_reg1; 3860 soc_reg_t reg; 3861 int set_index, cosq, numq; 3862 uint32 entry[SOC_MAX_MEM_WORDS]; 3863 static const soc_field_t fields[] = { 3864 S3_GROUP_NO_I0f, S3_GROUP_NO_I1f, S3_GROUP_NO_I2f, S3_GROUP_NO_I3f, 3865 S3_GROUP_NO_I4f, S3_GROUP_NO_I5f, S3_GROUP_NO_I6f, S3_GROUP_NO_I7f, 3866 S3_GROUP_NO_I8f 3867 }; 3868 uint32 num_cosq; 3869 3870 SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size)); 3871 if ((stable_size == 0) || (SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit))) { 3872 /* COSQ warmboot requires extended scache support i.e. level2 warmboot*/ 3873 return BCM_E_NONE; 3874 } 3875 3876 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 0); 3877 rv = _bcm_esw_scache_ptr_get(unit, scache_handle, FALSE, 0, &scache_ptr, 3878 BCM_WB_DEFAULT_VERSION, &recovered_ver); 3879 if (BCM_FAILURE(rv)) { 3880 return rv; 3881 } 3882 3883 si = &SOC_INFO(unit); 3884 3885 /* WB version 1.1 state starts at the end of scache for 1.0 version */ 3886 scache_ptr_2 = scache_ptr + 3887 _bcm_td_cosq_wb_alloc_size_get(unit, BCM_WB_VERSION_1_0); 3888 3889 PBMP_ALL_ITER(unit, port) { 3890 if (IS_CPU_PORT(unit, port)) { 3891 continue; 3892 } 3893 port_info = &_bcm_td_cosq_port_info[unit][port]; 3894 3895 /* Retrieve unicast queue info from scache */ 3896 map = scache_ptr; 3897 scache_ptr++; 3898 for (index = 0; index < _BCM_TD_NUM_NON_SC_QM_UCAST_QUEUE; index++) { 3899 if ((*map & (1 << index)) == 0) { 3900 continue; 3901 } 3902 node = &port_info->ucast[index]; 3903 node->numq = 1; 3904 value = GET_FIELD(UCAST_COSQ, *scache_ptr); 3905 node->cosq_attached_to = 3906 value == _BCM_TD_COSQ_WB_UCAST_COSQ_MASK ? -1 : value; 3907 node->base = GET_FIELD(UCAST_BASE, *scache_ptr); 3908 scache_ptr++; 3909 } 3910 3911 /* Retrieve unicast SC/QM queue info from scache */ 3912 /* Note that scache_ptr_2 is used here for recovering this info */ 3913 if (recovered_ver >= BCM_WB_VERSION_1_1) { 3914 map_2 = scache_ptr_2; 3915 scache_ptr_2++; 3916 for (index = _BCM_TD_NUM_NON_SC_QM_UCAST_QUEUE; 3917 index < _BCM_TD_NUM_UCAST_QUEUE_GROUP; 3918 index++) { 3919 3920 if ((*map_2 & 3921 (1 << (index - _BCM_TD_NUM_NON_SC_QM_UCAST_QUEUE))) == 0) { 3922 continue; 3923 } 3924 node = &port_info->ucast[index]; 3925 node->numq = 1; 3926 value = GET_FIELD(UCAST_COSQ, *scache_ptr_2); 3927 node->cosq_attached_to = GET_FIELD(UCAST_BASE, *scache_ptr_2); 3928 node->base = value - 10; 3929 scache_ptr_2++; 3930 } 3931 } 3932 3933 /* Retrieve multicast queue info from scache */ 3934 map = scache_ptr; 3935 scache_ptr++; 3936 for (index = 0; index < _BCM_TD_NUM_MCAST_QUEUE_GROUP; index++) { 3937 if ((*map & (1 << index)) == 0) { 3938 continue; 3939 } 3940 node = &port_info->mcast[index]; 3941 node->numq = 1; 3942 value = GET_FIELD(MCAST_COSQ, *scache_ptr); 3943 node->cosq_attached_to = 3944 value == _BCM_TD_COSQ_WB_MCAST_COSQ_MASK ? -1 : value; 3945 node->base = GET_FIELD(MCAST_BASE, *scache_ptr); 3946 scache_ptr++; 3947 } 3948 3949 /* Retrieve extended unicast queue info from scache */ 3950 if (si->port_num_ext_cosq[port] != 0) { 3951 map = scache_ptr; 3952 scache_ptr += 2; 3953 for (index = 0; index < _BCM_TD_NUM_EXT_UCAST_QUEUE_GROUP; 3954 index++) { 3955 if ((map[index >> 3] & (1 << (index & 0x07))) == 0) { 3956 continue; 3957 } 3958 node = &port_info->ext_ucast[index]; 3959 value = GET_FIELD(EXT_UCAST_COSQ, *scache_ptr); 3960 node->cosq_attached_to = 3961 value == _BCM_TD_COSQ_WB_EXT_UCAST_COSQ_MASK ? -1 : value; 3962 node->numq = GET_FIELD(EXT_UCAST_NUMQ, *scache_ptr); 3963 scache_ptr++; 3964 if (node->cosq_attached_to != -1) { 3965 node->base = GET_FIELD(EXT_UCAST_BASE, *scache_ptr); 3966 scache_ptr++; 3967 } 3968 } 3969 } 3970 3971 /* Retrieve scheduler info from scache */ 3972 map = scache_ptr; 3973 scache_ptr += 2; 3974 for (index = 0; index < _BCM_TD_NUM_SCHEDULER; index++) { 3975 if ((map[index >> 3] & (1 << (index & 0x07))) == 0) { 3976 continue; 3977 } 3978 node = &port_info->sched[index]; 3979 node->level = GET_FIELD(SCHED_LEVEL, *scache_ptr); 3980 node->numq = GET_FIELD(SCHED_NUMQ, *scache_ptr); 3981 scache_ptr++; 3982 if (node->level != 0) { 3983 value = GET_FIELD(SCHED_COSQ, *scache_ptr); 3984 node->cosq_attached_to = 3985 value == _BCM_TD_COSQ_WB_SCHED_COSQ_MASK ? -1 : value; 3986 value = GET_FIELD(SCHED_HW_COSQ, *scache_ptr); 3987 node->hw_cosq_attached_to = 3988 value == _BCM_TD_COSQ_WB_SCHED_HW_COSQ_MASK ? -1 : value; 3989 scache_ptr++; 3990 } else { 3991 node->cosq_attached_to = -1; 3992 node->hw_cosq_attached_to = -1; 3993 } 3994 } 3995 } 3996 /* Number COSQ */ 3997 sal_memcpy(&num_cosq, scache_ptr_2, sizeof(num_cosq)); 3998 if (!num_cosq) { 3999 /*sync didn't happen in the previous boot */ 4000 num_cosq = _bcm_esw_cosq_config_property_get(unit); 4001 } 4002 _bcm_td_num_cosq[unit] = num_cosq; 4003 4004 /* Ideally this equation holds good for all incremental versions */ 4005 additional_scache_size = 4006 _bcm_td_cosq_wb_alloc_size_get(unit, BCM_WB_DEFAULT_VERSION) - 4007 _bcm_td_cosq_wb_alloc_size_get(unit, recovered_ver); 4008 4009 /* Need to realloc unavailable space for subsequent syncs */ 4010 SOC_IF_ERROR_RETURN 4011 (soc_scache_realloc(unit, scache_handle, additional_scache_size)); 4012 4013 PBMP_ALL_ITER(unit, port) { 4014 if (IS_CPU_PORT(unit, port)) { 4015 continue; 4016 } 4017 port_info = &_bcm_td_cosq_port_info[unit][port]; 4018 4019 /* Retrieve info from hardware */ 4020 for (s2_index = 0; s2_index < _BCM_TD_NUM_S2_SCHEDULER; s2_index++) { 4021 s2_input[s2_index] = 0; 4022 BCM_IF_ERROR_RETURN 4023 (READ_S2_S3_ROUTINGr(unit, port, s2_index, &rval64)); 4024 for (index = 0; index < _BCM_TD_S2_SCHEDULER_NUM_INPUT; index++) { 4025 hw_cosq = soc_reg64_field32_get(unit, S2_S3_ROUTINGr, rval64, 4026 fields[index]); 4027 if (hw_cosq != 0x1f) { 4028 s2_input[s2_index] |= 1 << hw_cosq; 4029 } 4030 } 4031 } 4032 BCM_IF_ERROR_RETURN(READ_S3_CONFIGr(unit, port, &rval)); 4033 uc_to_s2 = soc_reg_field_get(unit, S3_CONFIGr, rval, ROUTE_UC_TO_S2f); 4034 BCM_IF_ERROR_RETURN(READ_S3_CONFIG_MCr(unit, port, &rval)); 4035 use_mc_group = soc_reg_field_get(unit, S3_CONFIG_MCr, rval, 4036 USE_MC_GROUPf); 4037 4038 /* Get modid */ 4039 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &local_modid)); 4040 BCM_IF_ERROR_RETURN 4041 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET, local_modid, 4042 port, &modid_out, &port_out)); 4043 4044 s1_node = NULL; 4045 s2_node[0] = s2_node[1] = s2_node[2] = NULL; 4046 s3_node[0] = s3_node[1] = s3_node[2] = s3_node[3] = NULL; 4047 mcg_node = NULL; 4048 4049 /* Recover software state of scheduler */ 4050 for (index = 0; index < _BCM_TD_NUM_SCHEDULER; index++) { 4051 node = &port_info->sched[index]; 4052 if (node->numq == 0) { 4053 continue; 4054 } 4055 sched_encap = (index << 16) | (modid_out << 8) | port_out; 4056 BCM_GPORT_SCHEDULER_SET(node->gport, sched_encap); 4057 if (node->cosq_attached_to == -1) { 4058 continue; 4059 } 4060 if (node->level == 1) { 4061 s1_node = node; 4062 } else if (node->level == 2) { 4063 if (node->hw_cosq_attached_to == 0) { 4064 mcg_node = node; 4065 } else if (node->hw_cosq_attached_to != -1) { 4066 s2_node[node->hw_cosq_attached_to - 1] = node; 4067 } 4068 } else if (node->level == 3) { 4069 if (node->hw_cosq_attached_to != -1) { 4070 s3_node[node->hw_cosq_attached_to] = node; 4071 } 4072 } 4073 } 4074 4075 if (s1_node == NULL) 4076 continue; 4077 4078 /* Recover software state of S2 scheduler */ 4079 for (index = 0; index < _BCM_TD_NUM_S2_SCHEDULER; index++) { 4080 if (s2_node[index] == NULL) { 4081 continue; 4082 } 4083 s2_node[index]->parent = s1_node; 4084 s2_node[index]->sibling = s1_node->child; 4085 s1_node->child = s2_node[index]; 4086 } 4087 4088 /* Recover software state of S3 scheduler */ 4089 for (index = 0; index < _BCM_TD_NUM_S3_SCHEDULER; index++) { 4090 if (s3_node[index] == NULL) { 4091 continue; 4092 } 4093 hw_cosq = index; 4094 for (s2_index = 0; s2_index < _BCM_TD_NUM_S2_SCHEDULER; 4095 s2_index++) { 4096 if (s2_input[s2_index] & (1 << hw_cosq)) { 4097 s3_node[index]->parent = s2_node[s2_index]; 4098 s3_node[index]->sibling = s2_node[s2_index]->child; 4099 s2_node[s2_index]->child = s3_node[index]; 4100 break; 4101 } 4102 } 4103 } 4104 4105 /* Recover software state of unicast queue */ 4106 for (index = 0; index < _BCM_TD_NUM_UCAST_QUEUE_GROUP; index++) { 4107 node = &port_info->ucast[index]; 4108 if (node->numq == 0) { 4109 continue; 4110 } 4111 BCM_GPORT_UCAST_QUEUE_GROUP_SYSQID_SET(node->gport, port, index); 4112 if (node->cosq_attached_to == -1) { 4113 node->hw_cosq_attached_to = -1; 4114 continue; 4115 } 4116 if (node->base > 7) { /* unicast SC or QM queue */ 4117 node->parent = s1_node; 4118 node->sibling = s1_node->child; 4119 s1_node->child = node; 4120 node->hw_cosq_attached_to = node->base - 3; /* 5 or 6 */ 4121 } else if (uc_to_s2 || node->base >= 4) { 4122 hw_cosq = node->base + 4; 4123 for (s2_index = 0; s2_index < _BCM_TD_NUM_S2_SCHEDULER; 4124 s2_index++) { 4125 if (s2_input[s2_index] & (1 << hw_cosq)) { 4126 node->parent = s2_node[s2_index]; 4127 node->sibling = s2_node[s2_index]->child; 4128 s2_node[s2_index]->child = node; 4129 node->hw_cosq_attached_to = hw_cosq; 4130 break; 4131 } 4132 } 4133 } else { 4134 node->parent = s3_node[node->base]; 4135 node->sibling = s3_node[node->base]->child; 4136 s3_node[node->base]->child = node; 4137 node->hw_cosq_attached_to = 1; 4138 } 4139 } 4140 4141 /* Recover software state of multicast queue */ 4142 for (index = 0; index < _BCM_TD_NUM_MCAST_QUEUE_GROUP; index++) { 4143 node = &port_info->mcast[index]; 4144 if (node->numq == 0) { 4145 continue; 4146 } 4147 BCM_GPORT_MCAST_QUEUE_GROUP_SYSQID_SET(node->gport, port, index); 4148 if (node->cosq_attached_to == -1) { 4149 node->hw_cosq_attached_to = -1; 4150 continue; 4151 } 4152 if (node->base > 3) { /* multicast SC/QM queue */ 4153 node->parent = s1_node; 4154 node->sibling = s1_node->child; 4155 s1_node->child = node; 4156 node->hw_cosq_attached_to = 4; 4157 } else if (use_mc_group) { 4158 node->parent = mcg_node; 4159 node->sibling = mcg_node->child; 4160 mcg_node->child = node; 4161 node->hw_cosq_attached_to = node->base; 4162 } else { 4163 node->parent = s3_node[node->base]; 4164 node->sibling = s3_node[node->base]->child; 4165 s3_node[node->base]->child = node; 4166 node->hw_cosq_attached_to = 0; 4167 } 4168 } 4169 4170 /* Recover software state of extended unicast queue */ 4171 for (index = 0; index < _BCM_TD_NUM_EXT_UCAST_QUEUE_GROUP; index++) { 4172 node = &port_info->ext_ucast[index]; 4173 if (node->numq == 0) { 4174 continue; 4175 } 4176 BCM_GPORT_UCAST_QUEUE_GROUP_SYSQID_SET 4177 (node->gport, port, _BCM_TD_NUM_UCAST_QUEUE_GROUP + index); 4178 if (node->cosq_attached_to == -1) { 4179 node->hw_cosq_attached_to = -1; 4180 continue; 4181 } 4182 node->parent = s3_node[node->base]; 4183 node->sibling = s3_node[node->base]->child; 4184 s3_node[node->base]->child = node; 4185 node->hw_cosq_attached_to = node->base + 2; 4186 } 4187 } 4188 4189 /* Update PORT_COS_MAP memory profile reference counter */ 4190 profile_mem = _bcm_td_cos_map_profile[unit]; 4191 PBMP_ALL_ITER(unit, port) { 4192 SOC_IF_ERROR_RETURN 4193 (soc_mem_read(unit, COS_MAP_SELm, MEM_BLOCK_ALL, port, &entry)); 4194 set_index = soc_mem_field32_get(unit, COS_MAP_SELm, &entry, SELECTf); 4195 SOC_IF_ERROR_RETURN 4196 (soc_profile_mem_reference(unit, profile_mem, set_index * 16, 16)); 4197 } 4198 if (SOC_INFO(unit).cpu_hg_index != -1) { 4199 SOC_IF_ERROR_RETURN(soc_mem_read(unit, COS_MAP_SELm, MEM_BLOCK_ALL, 4200 SOC_INFO(unit).cpu_hg_index, &entry)); 4201 set_index = soc_mem_field32_get(unit, COS_MAP_SELm, &entry, SELECTf); 4202 SOC_IF_ERROR_RETURN 4203 (soc_profile_mem_reference(unit, profile_mem, set_index, 1)); 4204 } 4205 4206 4207 4208 /* Update MMU_WRED_DROP_CURVE_PROFILE_x memory profile reference counter */ 4209 profile_mem = _bcm_td_wred_profile[unit]; 4210 PBMP_PORT_ITER(unit, port) { 4211 if (SOC_INFO(unit).port_num_ext_cosq[port] == 0) { /* regular port */ 4212 reg = WRED_CONFIGr; 4213 } else { /* extended queue port */ 4214 reg = DMVOQ_WRED_CONFIGr; 4215 } 4216 BCM_IF_ERROR_RETURN 4217 (_bcm_td_cosq_index_resolve(unit, port, -1, 4218 _BCM_TD_COSQ_INDEX_STYLE_WRED, NULL, 4219 NULL, &numq)); 4220 for (cosq = 0; cosq < numq; cosq++) { 4221 BCM_IF_ERROR_RETURN 4222 (_bcm_td_cosq_index_resolve(unit, port, cosq, 4223 _BCM_TD_COSQ_INDEX_STYLE_WRED, 4224 NULL, &index, NULL)); 4225 addr = soc_reg_addr(unit, reg, port, index); 4226 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, addr, &rval)); 4227 set_index = soc_reg_field_get(unit, reg, rval, PROFILE_INDEXf); 4228 SOC_IF_ERROR_RETURN 4229 (soc_profile_mem_reference(unit, profile_mem, set_index, 1)); 4230 } 4231 } 4232 4233 /* Update MMU_QCN_SITB memory profile and MMU_QCN_CFP_SEQ register profile 4234 * reference counter */ 4235 profile_mem = _bcm_td_sample_int_profile[unit]; 4236 profile_reg0 = _bcm_td_feedback_profile[unit]; 4237 numq = sizeof(_bcm_td_cpq_en_field) / sizeof(_bcm_td_cpq_en_field[0]); 4238 PBMP_PORT_ITER(unit, port) { 4239 phy_port = si->port_l2p_mapping[port]; 4240 mmu_port = si->port_p2m_mapping[phy_port]; 4241 SOC_IF_ERROR_RETURN(soc_mem_read(unit, MMU_QCN_ENABLEm, MEM_BLOCK_ANY, 4242 mmu_port, &entry)); 4243 for (cosq = 0; cosq < numq; cosq++) { 4244 if (!soc_mem_field32_get(unit, MMU_QCN_ENABLEm, &entry, 4245 _bcm_td_cpq_en_field[cosq])) { 4246 continue; 4247 } 4248 index = soc_mem_field32_get(unit, MMU_QCN_ENABLEm, &entry, 4249 _bcm_td_cpq_index_field[cosq]); 4250 SOC_IF_ERROR_RETURN(soc_mem_read(unit, MMU_QCN_CPQCFGm, 4251 MEM_BLOCK_ANY, mmu_port, &entry)); 4252 set_index = soc_mem_field32_get(unit, MMU_QCN_CPQCFGm, &entry, 4253 _bcm_td_sitb_sel_field[index]); 4254 SOC_IF_ERROR_RETURN 4255 (soc_profile_mem_reference(unit, profile_mem, set_index * 64, 4256 64)); 4257 set_index = soc_mem_field32_get(unit, MMU_QCN_CPQCFGm, &entry, 4258 _bcm_td_eqtb_index_field[index]); 4259 SOC_IF_ERROR_RETURN 4260 (soc_profile_reg_reference(unit, profile_reg0, set_index, 1)); 4261 } 4262 } 4263 4264 /* Update PRIO2COS_LLFC and PRIO2EXTQ_LLFC register profile reference 4265 * counter */ 4266 profile_reg0 = _bcm_td_llfc_profile[unit]; 4267 profile_reg1 = _bcm_td_ext_llfc_profile[unit]; 4268 PBMP_ALL_ITER(unit, port) { 4269 if (IS_CPU_PORT(unit, port)) { 4270 continue; 4271 } 4272 SOC_IF_ERROR_RETURN(READ_PORT_LLFC_CFGr(unit, port, &rval)); 4273 set_index = soc_reg_field_get(unit, PORT_LLFC_CFGr, rval, 4274 PROFILE_INDEXf); 4275 SOC_IF_ERROR_RETURN 4276 (soc_profile_reg_reference(unit, profile_reg0, set_index * 16, 4277 16)); 4278 set_index = soc_reg_field_get(unit, PORT_LLFC_CFGr, rval, 4279 EXT_PER_Q_INDEXf); 4280 SOC_IF_ERROR_RETURN 4281 (soc_profile_reg_reference(unit, profile_reg1, set_index * 16, 4282 16)); 4283 } 4284 4285 return BCM_E_NONE; 4286 } 4287 #endif /* BCM_WARM_BOOT_SUPPORT */ 4288 4289 /* 4290 * Function: 4291 * bcm_td_cosq_init 4292 * Purpose: 4293 * Initialize (clear) all COS schedule/mapping state. 4294 * Parameters: 4295 * unit - unit number 4296 * Returns: 4297 * BCM_E_XXX 4298 */ 4299 int 4300 bcm_td_cosq_init(int unit) 4301 { 4302 STATIC int _td_max_cosq = -1; 4303 int cosq, numq, alloc_size, i; 4304 bcm_port_t port; 4305 soc_reg_t reg; 4306 soc_reg_t mem; 4307 static soc_mem_t wred_mems[6] = { 4308 MMU_WRED_DROP_CURVE_PROFILE_0m, MMU_WRED_DROP_CURVE_PROFILE_1m, 4309 MMU_WRED_DROP_CURVE_PROFILE_2m, MMU_WRED_DROP_CURVE_PROFILE_3m, 4310 MMU_WRED_DROP_CURVE_PROFILE_4m, MMU_WRED_DROP_CURVE_PROFILE_5m 4311 }; 4312 int entry_words[6]; 4313 mmu_wred_drop_curve_profile_0_entry_t entry_tcp_green; 4314 mmu_wred_drop_curve_profile_1_entry_t entry_tcp_yellow; 4315 mmu_wred_drop_curve_profile_2_entry_t entry_tcp_red; 4316 mmu_wred_drop_curve_profile_3_entry_t entry_nontcp_green; 4317 mmu_wred_drop_curve_profile_4_entry_t entry_nontcp_yellow; 4318 mmu_wred_drop_curve_profile_5_entry_t entry_nontcp_red; 4319 void *entries[6]; 4320 uint64 rval64[16], *rval64s[1]; 4321 uint32 profile_index, rval; 4322 soc_info_t *si; 4323 4324 if (_td_max_cosq < 0) { 4325 _td_max_cosq = NUM_COS(unit); 4326 NUM_COS(unit) = 8; 4327 } 4328 4329 if (!SOC_WARM_BOOT(unit)) { /* Cold Boot */ 4330 BCM_IF_ERROR_RETURN (bcm_td_cosq_detach(unit, 0)); 4331 } 4332 4333 numq = soc_property_get(unit, spn_BCM_NUM_COS, BCM_COS_DEFAULT); 4334 4335 if (numq < 1) { 4336 numq = 1; 4337 } else if (numq > 8) { 4338 numq = 8; 4339 } 4340 4341 if (!cosq_sync_lock[unit]) { 4342 cosq_sync_lock[unit] = sal_mutex_create("TD cosq sync lock"); 4343 if (cosq_sync_lock[unit] == NULL) { 4344 return BCM_E_MEMORY; 4345 } 4346 } 4347 4348 si = &SOC_INFO(unit); 4349 /* Create ETS port information structures */ 4350 alloc_size = sizeof(_bcm_td_cosq_port_info_t) * 66; 4351 if (_bcm_td_cosq_port_info[unit] == NULL) { 4352 _bcm_td_cosq_port_info[unit] = 4353 sal_alloc(alloc_size, "_bcm_td_cosq_port_info"); 4354 } 4355 sal_memset(_bcm_td_cosq_port_info[unit], 0, alloc_size); 4356 4357 /* Create profile for PORT_COS_MAP table */ 4358 if (_bcm_td_cos_map_profile[unit] == NULL) { 4359 _bcm_td_cos_map_profile[unit] = sal_alloc(sizeof(soc_profile_mem_t), 4360 "COS_MAP Profile Mem"); 4361 if (_bcm_td_cos_map_profile[unit] == NULL) { 4362 return BCM_E_MEMORY; 4363 } 4364 soc_profile_mem_t_init(_bcm_td_cos_map_profile[unit]); 4365 } 4366 mem = PORT_COS_MAPm; 4367 entry_words[0] = sizeof(port_cos_map_entry_t) / sizeof(uint32); 4368 BCM_IF_ERROR_RETURN(soc_profile_mem_create(unit, &mem, entry_words, 1, 4369 _bcm_td_cos_map_profile[unit])); 4370 4371 /* Create profile for VOQ_COS_MAP table */ 4372 if (_bcm_td_voq_cos_map_profile[unit] == NULL) { 4373 _bcm_td_voq_cos_map_profile[unit] = 4374 sal_alloc(sizeof(soc_profile_mem_t), "VOQ_COS_MAP Profile Mem"); 4375 if (_bcm_td_voq_cos_map_profile[unit] == NULL) { 4376 return BCM_E_MEMORY; 4377 } 4378 soc_profile_mem_t_init(_bcm_td_voq_cos_map_profile[unit]); 4379 } 4380 mem = VOQ_COS_MAPm; 4381 entry_words[0] = sizeof(voq_cos_map_entry_t) / sizeof(uint32); 4382 BCM_IF_ERROR_RETURN 4383 (soc_profile_mem_create(unit, &mem, entry_words, 1, 4384 _bcm_td_voq_cos_map_profile[unit])); 4385 4386 /* Create profile for MMU_WRED_DROP_CURVE_PROFILE_x tables */ 4387 if (_bcm_td_wred_profile[unit] == NULL) { 4388 _bcm_td_wred_profile[unit] = sal_alloc(sizeof(soc_profile_mem_t), 4389 "WRED Profile Mem"); 4390 if (_bcm_td_wred_profile[unit] == NULL) { 4391 return BCM_E_MEMORY; 4392 } 4393 soc_profile_mem_t_init(_bcm_td_wred_profile[unit]); 4394 } 4395 entry_words[0] = 4396 sizeof(mmu_wred_drop_curve_profile_0_entry_t) / sizeof(uint32); 4397 entry_words[1] = 4398 sizeof(mmu_wred_drop_curve_profile_1_entry_t) / sizeof(uint32); 4399 entry_words[2] = 4400 sizeof(mmu_wred_drop_curve_profile_2_entry_t) / sizeof(uint32); 4401 entry_words[3] = 4402 sizeof(mmu_wred_drop_curve_profile_3_entry_t) / sizeof(uint32); 4403 entry_words[4] = 4404 sizeof(mmu_wred_drop_curve_profile_4_entry_t) / sizeof(uint32); 4405 entry_words[5] = 4406 sizeof(mmu_wred_drop_curve_profile_5_entry_t) / sizeof(uint32); 4407 BCM_IF_ERROR_RETURN 4408 (soc_profile_mem_create(unit, wred_mems, entry_words, 6, 4409 _bcm_td_wred_profile[unit])); 4410 4411 /* Create profile for MMU_QCN_SITB table */ 4412 if (_bcm_td_sample_int_profile[unit] == NULL) { 4413 _bcm_td_sample_int_profile[unit] = 4414 sal_alloc(sizeof(soc_profile_mem_t), "QCN sample Int Profile Mem"); 4415 if (_bcm_td_sample_int_profile[unit] == NULL) { 4416 return BCM_E_MEMORY; 4417 } 4418 soc_profile_mem_t_init(_bcm_td_sample_int_profile[unit]); 4419 } 4420 mem = MMU_QCN_SITBm; 4421 entry_words[0] = sizeof(mmu_qcn_sitb_entry_t) / sizeof(uint32); 4422 BCM_IF_ERROR_RETURN 4423 (soc_profile_mem_create(unit, &mem, entry_words, 1, 4424 _bcm_td_sample_int_profile[unit])); 4425 4426 /* Create profile for MMU_QCN_CPQ_SEQ register */ 4427 if (_bcm_td_feedback_profile[unit] == NULL) { 4428 _bcm_td_feedback_profile[unit] = 4429 sal_alloc(sizeof(soc_profile_reg_t), "QCN Feedback Profile Reg"); 4430 if (_bcm_td_feedback_profile[unit] == NULL) { 4431 return BCM_E_MEMORY; 4432 } 4433 soc_profile_reg_t_init(_bcm_td_feedback_profile[unit]); 4434 } 4435 reg = MMU_QCN_CPQ_SEQr; 4436 BCM_IF_ERROR_RETURN 4437 (soc_profile_reg_create(unit, ®, 1, 4438 _bcm_td_feedback_profile[unit])); 4439 4440 /* Create profile for PRIO2COS_LLFC register */ 4441 if (_bcm_td_llfc_profile[unit] == NULL) { 4442 _bcm_td_llfc_profile[unit] = 4443 sal_alloc(sizeof(soc_profile_reg_t), "PRIO2COS_LLFC Profile Reg"); 4444 if (_bcm_td_llfc_profile[unit] == NULL) { 4445 return BCM_E_MEMORY; 4446 } 4447 soc_profile_reg_t_init(_bcm_td_llfc_profile[unit]); 4448 } 4449 reg = PRIO2COS_LLFCr; 4450 BCM_IF_ERROR_RETURN 4451 (soc_profile_reg_create(unit, ®, 1, _bcm_td_llfc_profile[unit])); 4452 4453 /* Create profile for PRIO2EXTQ_LLFC register */ 4454 if (_bcm_td_ext_llfc_profile[unit] == NULL) { 4455 _bcm_td_ext_llfc_profile[unit] = 4456 sal_alloc(sizeof(soc_profile_reg_t), "PRIO2EXTQ_LLFC Profile Reg"); 4457 if (_bcm_td_ext_llfc_profile[unit] == NULL) { 4458 return BCM_E_MEMORY; 4459 } 4460 soc_profile_reg_t_init(_bcm_td_ext_llfc_profile[unit]); 4461 } 4462 reg = PRIO2EXTQ_LLFCr; 4463 BCM_IF_ERROR_RETURN 4464 (soc_profile_reg_create(unit, ®, 1, 4465 _bcm_td_ext_llfc_profile[unit])); 4466 4467 for (i = 0; i < si->num_cpu_cosq; i++) { 4468 if (_bcm_td_cosq_cpu_cosq_config[unit][i] == NULL) { 4469 _bcm_td_cosq_cpu_cosq_config[unit][i] = 4470 sal_alloc(sizeof(_bcm_td_cosq_cpu_cosq_config_t), "CPU Cosq Config"); 4471 4472 if (_bcm_td_cosq_cpu_cosq_config[unit][i] == NULL) { 4473 return BCM_E_MEMORY; 4474 } 4475 sal_memset(_bcm_td_cosq_cpu_cosq_config[unit][i], 0, 4476 sizeof(_bcm_td_cosq_cpu_cosq_config_t)); 4477 _bcm_td_cosq_cpu_cosq_config[unit][i]->enable = 1; 4478 } 4479 } 4480 4481 #ifdef BCM_WARM_BOOT_SUPPORT 4482 if (SOC_WARM_BOOT(unit)) { 4483 return bcm_td_cosq_reinit(unit); 4484 } else { 4485 BCM_IF_ERROR_RETURN(_bcm_td_cosq_wb_alloc(unit)); 4486 } 4487 #endif /* BCM_WARM_BOOT_SUPPORT */ 4488 4489 /* Add default entries for PORT_COS_MAP memory profile */ 4490 BCM_IF_ERROR_RETURN(_bcm_td_cosq_config_set(unit, numq)); 4491 4492 /* Add default entries for VOQ_COS_MAP memory profile */ 4493 PBMP_PORT_ITER(unit, port) { 4494 if (!_BCM_TD_IS_PORT_DMVOQ_CAPABLE(unit, port)) { 4495 continue; 4496 } 4497 BCM_IF_ERROR_RETURN(_bcm_td_cosq_voq_init(unit, port)); 4498 } 4499 4500 /* Add default entries for MMU_WRED_DROP_CURVE_PROFILE_x memory profile */ 4501 sal_memset(&entry_tcp_green, 0, sizeof(entry_tcp_green)); 4502 sal_memset(&entry_tcp_yellow, 0, sizeof(entry_tcp_yellow)); 4503 sal_memset(&entry_tcp_red, 0, sizeof(entry_tcp_red)); 4504 sal_memset(&entry_nontcp_green, 0, sizeof(entry_nontcp_green)); 4505 sal_memset(&entry_nontcp_yellow, 0, sizeof(entry_nontcp_yellow)); 4506 sal_memset(&entry_nontcp_red, 0, sizeof(entry_nontcp_red)); 4507 entries[0] = &entry_tcp_green; 4508 entries[1] = &entry_tcp_yellow; 4509 entries[2] = &entry_tcp_red; 4510 entries[3] = &entry_nontcp_green; 4511 entries[4] = &entry_nontcp_yellow; 4512 entries[5] = &entry_nontcp_red; 4513 for (i = 0; i < 6; i++) { 4514 soc_mem_field32_set(unit, wred_mems[i], entries[i], 4515 MIN_THDf, 0xffff); 4516 soc_mem_field32_set(unit, wred_mems[i], entries[i], 4517 MAX_THDf, 0xffff); 4518 } 4519 profile_index = 0xffffffff; 4520 PBMP_PORT_ITER(unit, port) { 4521 BCM_IF_ERROR_RETURN 4522 (_bcm_td_cosq_index_resolve(unit, port, -1, 4523 _BCM_TD_COSQ_INDEX_STYLE_WRED, NULL, 4524 NULL, &numq)); 4525 for (cosq = 0; cosq < numq; cosq++) { 4526 if (profile_index == 0xffffffff) { 4527 BCM_IF_ERROR_RETURN 4528 (soc_profile_mem_add(unit, _bcm_td_wred_profile[unit], 4529 entries, 1, &profile_index)); 4530 } else { 4531 BCM_IF_ERROR_RETURN 4532 (soc_profile_mem_reference(unit, 4533 _bcm_td_wred_profile[unit], 4534 profile_index, 0)); 4535 } 4536 } 4537 } 4538 4539 /* Add default entries for PRIO2COS_LLFC register profile */ 4540 sal_memset(rval64, 0, sizeof(rval64)); 4541 rval64s[0] = rval64; 4542 profile_index = 0xffffffff; 4543 PBMP_PORT_ITER(unit, port) { 4544 if (profile_index == 0xffffffff) { 4545 BCM_IF_ERROR_RETURN 4546 (soc_profile_reg_add(unit, _bcm_td_llfc_profile[unit], 4547 rval64s, 16, &profile_index)); 4548 } else { 4549 BCM_IF_ERROR_RETURN 4550 (soc_profile_reg_reference(unit, _bcm_td_llfc_profile[unit], 4551 profile_index, 0)); 4552 } 4553 } 4554 4555 /* Add default entries for PRIO2EXTQ_LLFC register profile */ 4556 profile_index = 0xffffffff; 4557 PBMP_PORT_ITER(unit, port) { 4558 if (profile_index == 0xffffffff) { 4559 BCM_IF_ERROR_RETURN 4560 (soc_profile_reg_add(unit, _bcm_td_ext_llfc_profile[unit], 4561 rval64s, 16, &profile_index)); 4562 } else { 4563 BCM_IF_ERROR_RETURN 4564 (soc_profile_reg_reference(unit, 4565 _bcm_td_ext_llfc_profile[unit], 4566 profile_index, 0)); 4567 } 4568 } 4569 4570 /* 4571 * Always strict priority for SC and QM COS queues 4572 * S1 COS4 is for multicast SC and QM queue 4573 * S1 COS5 is for unicast SC queue 4574 * S1 COS6 is for unicast QM queue 4575 */ 4576 PBMP_ALL_ITER(unit, port) { 4577 if (IS_CPU_PORT(unit, port)) { 4578 continue; 4579 } 4580 BCM_IF_ERROR_RETURN(READ_MINSPCONFIGr(unit, port, &rval)); 4581 soc_reg_field_set(unit, MINSPCONFIGr, &rval, COS4_IS_SPf, 1); 4582 soc_reg_field_set(unit, MINSPCONFIGr, &rval, COS5_IS_SPf, 1); 4583 soc_reg_field_set(unit, MINSPCONFIGr, &rval, COS6_IS_SPf, 1); 4584 BCM_IF_ERROR_RETURN(WRITE_MINSPCONFIGr(unit, port, rval)); 4585 } 4586 4587 return BCM_E_NONE; 4588 } 4589 4590 /* 4591 * Function: 4592 * bcm_td_cosq_detach 4593 * Purpose: 4594 * Discard all COS schedule/mapping state. 4595 * Parameters: 4596 * unit - unit number 4597 * Returns: 4598 * BCM_E_XXX 4599 */ 4600 int 4601 bcm_td_cosq_detach(int unit, int software_state_only) 4602 { 4603 int i; 4604 soc_info_t *si; 4605 4606 si = &SOC_INFO(unit); 4607 /* Cleanup ETS port information structures */ 4608 if (_bcm_td_cosq_port_info[unit] != NULL) { 4609 sal_free(_bcm_td_cosq_port_info[unit]); 4610 _bcm_td_cosq_port_info[unit] = NULL; 4611 } 4612 4613 /* Cleanup profile for PORT_COS_MAP table */ 4614 if (_bcm_td_cos_map_profile[unit] != NULL) { 4615 SOC_IF_ERROR_RETURN(soc_profile_mem_destroy(unit, 4616 _bcm_td_cos_map_profile[unit])); 4617 sal_free(_bcm_td_cos_map_profile[unit]); 4618 _bcm_td_cos_map_profile[unit] = NULL; 4619 } 4620 4621 /* Cleanup profile for VOQ_COS_MAP table */ 4622 if (_bcm_td_voq_cos_map_profile[unit] != NULL) { 4623 SOC_IF_ERROR_RETURN(soc_profile_mem_destroy(unit, 4624 _bcm_td_voq_cos_map_profile[unit])); 4625 sal_free(_bcm_td_voq_cos_map_profile[unit]); 4626 _bcm_td_voq_cos_map_profile[unit] = NULL; 4627 } 4628 4629 /* Cleanup profile for MMU_WRED_DROP_CURVE_PROFILE_x tables */ 4630 if (_bcm_td_wred_profile[unit] != NULL) { 4631 SOC_IF_ERROR_RETURN(soc_profile_mem_destroy(unit, 4632 _bcm_td_wred_profile[unit])); 4633 sal_free(_bcm_td_wred_profile[unit]); 4634 _bcm_td_wred_profile[unit] = NULL; 4635 } 4636 4637 /* Cleanup profile for MMU_QCN_SITB table */ 4638 if (_bcm_td_sample_int_profile[unit] != NULL) { 4639 SOC_IF_ERROR_RETURN(soc_profile_mem_destroy(unit, 4640 _bcm_td_sample_int_profile[unit])); 4641 sal_free(_bcm_td_sample_int_profile[unit]); 4642 _bcm_td_sample_int_profile[unit] = NULL; 4643 } 4644 4645 /* Cleanup profile for MMU_QCN_CPQ_SEQ register */ 4646 if (_bcm_td_feedback_profile[unit] != NULL) { 4647 SOC_IF_ERROR_RETURN(soc_profile_reg_destroy(unit, 4648 _bcm_td_feedback_profile[unit])); 4649 sal_free(_bcm_td_feedback_profile[unit]); 4650 _bcm_td_feedback_profile[unit] = NULL; 4651 } 4652 4653 /* Cleanup profile for PRIO2COS_LLFC register */ 4654 if (_bcm_td_llfc_profile[unit] != NULL) { 4655 SOC_IF_ERROR_RETURN(soc_profile_reg_destroy(unit, 4656 _bcm_td_llfc_profile[unit])); 4657 sal_free(_bcm_td_llfc_profile[unit]); 4658 _bcm_td_llfc_profile[unit] = NULL; 4659 } 4660 4661 /* Cleanup profile for PRIO2EXTQ_LLFC register */ 4662 if (_bcm_td_ext_llfc_profile[unit] != NULL) { 4663 SOC_IF_ERROR_RETURN(soc_profile_reg_destroy(unit, 4664 _bcm_td_ext_llfc_profile[unit])); 4665 sal_free(_bcm_td_ext_llfc_profile[unit]); 4666 _bcm_td_ext_llfc_profile[unit] = NULL; 4667 } 4668 4669 for (i = 0; i < si->num_cpu_cosq; i++) { 4670 if (_bcm_td_cosq_cpu_cosq_config[unit][i] != NULL) { 4671 sal_free(_bcm_td_cosq_cpu_cosq_config[unit][i]); 4672 _bcm_td_cosq_cpu_cosq_config[unit][i] = NULL; 4673 } 4674 } 4675 4676 if (cosq_sync_lock[unit]) { 4677 sal_mutex_destroy(cosq_sync_lock[unit]); 4678 cosq_sync_lock[unit] = NULL; 4679 } 4680 4681 return BCM_E_NONE; 4682 } 4683 4684 /* 4685 * Function: 4686 * bcm_td_cosq_config_set 4687 * Purpose: 4688 * Set the number of COS queues 4689 * Parameters: 4690 * unit - unit number 4691 * numq - number of COS queues (1-8). 4692 * Returns: 4693 * BCM_E_XXX 4694 */ 4695 int 4696 bcm_td_cosq_config_set(int unit, int numq) 4697 { 4698 soc_mem_t mem; 4699 int entry_words; 4700 4701 mem = PORT_COS_MAPm; 4702 entry_words = sizeof(port_cos_map_entry_t) / sizeof(uint32); 4703 BCM_IF_ERROR_RETURN(soc_profile_mem_create(unit, &mem, &entry_words, 1, 4704 _bcm_td_cos_map_profile[unit])); 4705 4706 return _bcm_td_cosq_config_set(unit, numq); 4707 } 4708 4709 /* 4710 * Function: 4711 * bcm_td_cosq_config_get 4712 * Purpose: 4713 * Get the number of cos queues 4714 * Parameters: 4715 * unit - unit number 4716 * numq - (Output) number of cosq 4717 * Returns: 4718 * BCM_E_XXX 4719 */ 4720 int 4721 bcm_td_cosq_config_get(int unit, int *numq) 4722 { 4723 if (_bcm_td_num_cosq[unit] == 0) { 4724 return BCM_E_INIT; 4725 } 4726 4727 if (numq != NULL) { 4728 *numq = _bcm_td_num_cosq[unit]; 4729 } 4730 4731 return BCM_E_NONE; 4732 } 4733 4734 /* 4735 * Function: 4736 * bcm_td_cosq_mapping_set 4737 * Purpose: 4738 * Set which cosq a given priority should fall into 4739 * Parameters: 4740 * unit - (IN) unit number 4741 * gport - (IN) queue group GPORT identifier 4742 * priority - (IN) priority value to map 4743 * cosq - (IN) COS queue to map to 4744 * Returns: 4745 * BCM_E_XXX 4746 */ 4747 int 4748 bcm_td_cosq_mapping_set(int unit, bcm_port_t port, bcm_cos_t priority, 4749 bcm_cos_queue_t cosq) 4750 { 4751 bcm_pbmp_t pbmp; 4752 bcm_port_t local_port; 4753 bcm_cos_queue_t mc_cosq_max, mc_cosq; 4754 4755 mc_cosq_max = (_BCM_TD_NUM_MCAST_QUEUE_GROUP - 1); 4756 4757 BCM_PBMP_CLEAR(pbmp); 4758 if (port == -1) { 4759 BCM_PBMP_ASSIGN(pbmp, PBMP_ALL(unit)); 4760 } else { 4761 if (BCM_GPORT_IS_SET(port)) { 4762 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port) || 4763 BCM_GPORT_IS_MCAST_QUEUE_GROUP(port) || 4764 BCM_GPORT_IS_SCHEDULER(port)) { 4765 return BCM_E_PARAM; 4766 } else if (BCM_GPORT_IS_LOCAL(port)) { 4767 local_port = BCM_GPORT_LOCAL_GET(port); 4768 } else { 4769 return BCM_E_PARAM; 4770 } 4771 } else { 4772 local_port = port; 4773 } 4774 if (!SOC_PORT_VALID(unit, local_port)) { 4775 return BCM_E_PORT; 4776 } 4777 BCM_PBMP_PORT_ADD(pbmp, local_port); 4778 } 4779 4780 if ((cosq < 0) || (cosq >= _TD_NUM_COS(unit))) { 4781 return BCM_E_PARAM; 4782 } 4783 PBMP_ITER(pbmp, local_port) { 4784 if (IS_LB_PORT(unit, local_port)) { 4785 continue; 4786 } 4787 /* If no gport, map the int prio symmetrically for ucast and 4788 * mcast 4789 * There are only 5 MC QUEUES [0,4] attached to a port 4790 */ 4791 mc_cosq = (cosq > mc_cosq_max) ? mc_cosq_max : cosq; 4792 BCM_IF_ERROR_RETURN(_bcm_td_cosq_mapping_set(unit, local_port, 4793 priority, 4794 BCM_COSQ_GPORT_UCAST_QUEUE_GROUP | BCM_COSQ_GPORT_MCAST_QUEUE_GROUP, 4795 -1, (cosq << 16 | (mc_cosq & 0xffff)))); 4796 } 4797 return BCM_E_NONE; 4798 4799 } 4800 4801 /* 4802 * Function: 4803 * bcm_td_cosq_mapping_get 4804 * Purpose: 4805 * Determine which COS queue a given priority currently maps to. 4806 * Parameters: 4807 * unit - (IN) unit number 4808 * gport - (IN) queue group GPORT identifier 4809 * priority - (IN) priority value to map 4810 * cosq - (OUT) COS queue to map to 4811 * Returns: 4812 * BCM_E_XXX 4813 */ 4814 int 4815 bcm_td_cosq_mapping_get(int unit, bcm_port_t port, bcm_cos_t priority, 4816 bcm_cos_queue_t *cosq) 4817 { 4818 bcm_port_t local_port; 4819 bcm_pbmp_t pbmp; 4820 4821 BCM_PBMP_CLEAR(pbmp); 4822 4823 if (port == -1) { 4824 BCM_PBMP_ASSIGN(pbmp, PBMP_ALL(unit)); 4825 } else { 4826 if (BCM_GPORT_IS_SET(port)) { 4827 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port) || 4828 BCM_GPORT_IS_MCAST_QUEUE_GROUP(port) || 4829 BCM_GPORT_IS_SCHEDULER(port)) { 4830 return BCM_E_PARAM; 4831 } else if (BCM_GPORT_IS_LOCAL(port)) { 4832 local_port = BCM_GPORT_LOCAL_GET(port); 4833 } else { 4834 return BCM_E_PARAM; 4835 } 4836 } else { 4837 local_port = port; 4838 } 4839 if (!SOC_PORT_VALID(unit, local_port)) { 4840 return BCM_E_PORT; 4841 } 4842 BCM_PBMP_PORT_ADD(pbmp, local_port); 4843 } 4844 4845 PBMP_ITER(pbmp, local_port) { 4846 if (IS_LB_PORT(unit, local_port)) { 4847 continue; 4848 } 4849 BCM_IF_ERROR_RETURN(_bcm_td_cosq_mapping_get(unit, local_port, 4850 priority, BCM_COSQ_GPORT_UCAST_QUEUE_GROUP, NULL, cosq)); 4851 break; 4852 } 4853 return BCM_E_NONE; 4854 } 4855 4856 /* 4857 * Function: 4858 * bcm_td_cosq_port_sched_set 4859 * Purpose: 4860 * Set up class-of-service policy and corresponding weights and delay 4861 * Parameters: 4862 * unit - (IN) unit number 4863 * pbm - (IN) port bitmap 4864 * mode - (IN) Scheduling mode (BCM_COSQ_xxx) 4865 * weights - (IN) Weights for each COS queue 4866 * delay - This parameter is not used 4867 * Returns: 4868 * BCM_E_XXX 4869 */ 4870 int 4871 bcm_td_cosq_port_sched_set(int unit, bcm_pbmp_t pbm, 4872 int mode, const int *weights, int delay) 4873 { 4874 bcm_port_t port; 4875 int num_weights; 4876 4877 BCM_PBMP_ITER(pbm, port) { 4878 /* coverity[overrun-local : FALSE] */ 4879 num_weights = _TD_NUM_COS(unit); 4880 BCM_IF_ERROR_RETURN 4881 (_bcm_td_cosq_sched_set(unit, port, 0, mode, num_weights, 4882 (int *)weights)); 4883 } 4884 4885 return BCM_E_NONE; 4886 } 4887 4888 /* 4889 * Function: 4890 * bcm_td_cosq_port_sched_get 4891 * Purpose: 4892 * Retrieve class-of-service policy and corresponding weights and delay 4893 * Parameters: 4894 * unit - (IN) unit number 4895 * pbm - (IN) port bitmap 4896 * mode - (OUT) Scheduling mode (BCM_COSQ_XXX) 4897 * weights - (OUT) Weights for each COS queue 4898 * delay - This parameter is not used 4899 * Returns: 4900 * BCM_E_XXX 4901 */ 4902 int 4903 bcm_td_cosq_port_sched_get(int unit, bcm_pbmp_t pbm, 4904 int *mode, int *weights, int *delay) 4905 { 4906 bcm_port_t port; 4907 4908 BCM_PBMP_ITER(pbm, port) { 4909 /* coverity[overrun-local : FALSE] */ 4910 /* coverity[illegal_address : FALSE] */ 4911 if (IS_CPU_PORT(unit, port) && SOC_PBMP_NEQ(pbm, PBMP_CMIC(unit))) { 4912 continue; 4913 } 4914 return _bcm_td_cosq_sched_get(unit, port, 0, mode, 8, weights); 4915 } 4916 4917 return BCM_E_PORT; 4918 } 4919 4920 /* 4921 * Function: 4922 * bcm_td_cosq_sched_weight_max_get 4923 * Purpose: 4924 * Retrieve maximum weights for given COS policy 4925 * Parameters: 4926 * unit - (IN) unit number 4927 * mode - (IN) Scheduling mode (BCM_COSQ_xxx) 4928 * weight_max - (OUT) Maximum weight for COS queue. 4929 * Returns: 4930 * BCM_E_XXX 4931 */ 4932 int 4933 bcm_td_cosq_sched_weight_max_get(int unit, int mode, int *weight_max) 4934 { 4935 switch (mode) { 4936 case BCM_COSQ_STRICT: 4937 *weight_max = BCM_COSQ_WEIGHT_STRICT; 4938 break; 4939 case BCM_COSQ_ROUND_ROBIN: 4940 *weight_max = BCM_COSQ_WEIGHT_MIN; 4941 break; 4942 case BCM_COSQ_WEIGHTED_ROUND_ROBIN: 4943 case BCM_COSQ_DEFICIT_ROUND_ROBIN: 4944 *weight_max = 4945 (1 << soc_reg_field_length(unit, COSWEIGHTSr, COSWEIGHTSf)) - 1; 4946 break; 4947 default: 4948 return BCM_E_PARAM; 4949 } 4950 4951 return BCM_E_NONE; 4952 } 4953 4954 /* 4955 * Function: 4956 * bcm_td_cosq_bandwidth_set 4957 * Purpose: 4958 * Configure COS queue bandwidth control 4959 * Parameters: 4960 * unit - (IN) unit number 4961 * port - (IN) port number or GPORT identifier 4962 * cosq - (IN) COS queue number 4963 * min_quantum - (IN) 4964 * max_quantum - (IN) 4965 * burst_quantum - (IN) 4966 * flags - (IN) 4967 * Returns: 4968 * BCM_E_XXX 4969 * Notes: 4970 * If port is any form of local port, cosq is the hardware queue index. 4971 */ 4972 int 4973 bcm_td_cosq_port_bandwidth_set(int unit, bcm_port_t port, 4974 bcm_cos_queue_t cosq, 4975 uint32 min_quantum, uint32 max_quantum, 4976 uint32 burst_quantum, uint32 flags) 4977 { 4978 if (cosq < 0) { 4979 return BCM_E_PARAM; 4980 } 4981 4982 return _bcm_td_cosq_bucket_set(unit, port, cosq, min_quantum, 4983 max_quantum, min_quantum, max_quantum, 4984 flags); 4985 } 4986 4987 /* 4988 * Function: 4989 * bcm_td_cosq_bandwidth_get 4990 * Purpose: 4991 * Get COS queue bandwidth control configuration 4992 * Parameters: 4993 * unit - (IN) unit number 4994 * port - (IN) port number or GPORT identifier 4995 * cosq - (IN) COS queue number 4996 * min_quantum - (OUT) 4997 * max_quantum - (OUT) 4998 * burst_quantum - (OUT) 4999 * flags - (OUT) 5000 * Returns: 5001 * BCM_E_XXX 5002 * Notes: 5003 * If port is any form of local port, cosq is the hardware queue index. 5004 */ 5005 int 5006 bcm_td_cosq_port_bandwidth_get(int unit, bcm_port_t port, 5007 bcm_cos_queue_t cosq, 5008 uint32 *min_quantum, uint32 *max_quantum, 5009 uint32 *burst_quantum, uint32 *flags) 5010 { 5011 uint32 tmp; 5012 5013 if (cosq < 0) { 5014 return BCM_E_PARAM; 5015 } 5016 5017 BCM_IF_ERROR_RETURN(_bcm_td_cosq_bucket_get(unit, port, cosq, min_quantum, 5018 max_quantum, &tmp, 5019 burst_quantum, flags)); 5020 5021 return BCM_E_NONE; 5022 } 5023 5024 int 5025 bcm_td_cosq_port_pps_set(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 5026 int pps) 5027 { 5028 uint32 min, max, burst, flags; 5029 5030 if (!IS_CPU_PORT(unit, port)) { 5031 return BCM_E_PORT; 5032 } else if (cosq < 0 || cosq >= NUM_CPU_COSQ(unit)) { 5033 return BCM_E_PARAM; 5034 } 5035 5036 /* Get the current PPS and BURST settings */ 5037 BCM_IF_ERROR_RETURN 5038 (_bcm_td_cosq_bucket_get(unit, port, cosq, &min, &max, &burst, &burst, 5039 &flags)); 5040 5041 5042 5043 /* Replace the current PPS setting, keep BURST the same */ 5044 return _bcm_td_cosq_bucket_set(unit, port, cosq, min, pps, burst, burst, 5045 flags | BCM_COSQ_BW_PACKET_MODE); 5046 } 5047 5048 int 5049 bcm_td_cosq_port_pps_get(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 5050 int *pps) 5051 { 5052 uint32 min, max, burst, flags; 5053 5054 if (!IS_CPU_PORT(unit, port)) { 5055 return BCM_E_PORT; 5056 } else if (cosq < 0 || cosq >= NUM_CPU_COSQ(unit)) { 5057 return BCM_E_PARAM; 5058 } 5059 5060 BCM_IF_ERROR_RETURN 5061 (_bcm_td_cosq_bucket_get(unit, port, cosq, &min, &max, &burst, &burst, 5062 &flags)); 5063 *pps = max; 5064 5065 return BCM_E_NONE; 5066 } 5067 5068 int 5069 bcm_td_cosq_port_burst_set(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 5070 int burst) 5071 { 5072 uint32 min, max, cur_burst, flags; 5073 5074 if (!IS_CPU_PORT(unit, port)) { 5075 return BCM_E_PORT; 5076 } else if (cosq < 0 || cosq >= NUM_CPU_COSQ(unit)) { 5077 return BCM_E_PARAM; 5078 } 5079 5080 /* Get the current PPS and BURST settings */ 5081 BCM_IF_ERROR_RETURN 5082 (_bcm_td_cosq_bucket_get(unit, port, cosq, &min, &max, &cur_burst, 5083 &cur_burst, &flags)); 5084 5085 5086 5087 /* Replace the current BURST setting, keep PPS the same */ 5088 return _bcm_td_cosq_bucket_set(unit, port, cosq, min, max, burst, burst, 5089 flags | BCM_COSQ_BW_PACKET_MODE); 5090 } 5091 5092 int 5093 bcm_td_cosq_port_burst_get(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 5094 int *burst) 5095 { 5096 uint32 min, max, cur_burst, flags, tmp; 5097 5098 if (!IS_CPU_PORT(unit, port)) { 5099 return BCM_E_PORT; 5100 } else if (cosq < 0 || cosq >= NUM_CPU_COSQ(unit)) { 5101 return BCM_E_PARAM; 5102 } 5103 5104 BCM_IF_ERROR_RETURN 5105 (_bcm_td_cosq_bucket_get(unit, port, cosq, &min, &max, &tmp, 5106 &cur_burst, &flags)); 5107 *burst = cur_burst; 5108 5109 return BCM_E_NONE; 5110 } 5111 5112 int 5113 bcm_td_cosq_discard_set(int unit, uint32 flags) 5114 { 5115 bcm_port_t port; 5116 bcm_cos_queue_t cosq; 5117 int numq; 5118 5119 if (flags & ~(BCM_COSQ_DISCARD_DEVICE | 5120 BCM_COSQ_DISCARD_NONTCP | 5121 BCM_COSQ_DISCARD_COLOR_ALL | 5122 BCM_COSQ_DISCARD_PORT | 5123 BCM_COSQ_DISCARD_TCP | 5124 BCM_COSQ_DISCARD_COLOR_GREEN | 5125 BCM_COSQ_DISCARD_COLOR_YELLOW | 5126 BCM_COSQ_DISCARD_COLOR_RED | 5127 BCM_COSQ_DISCARD_CAP_AVERAGE | 5128 BCM_COSQ_DISCARD_ENABLE | 5129 BCM_COSQ_DISCARD_MARK_CONGESTION)) { 5130 return BCM_E_PARAM; 5131 } 5132 5133 flags &= ~(BCM_COSQ_DISCARD_NONTCP | BCM_COSQ_DISCARD_COLOR_ALL); 5134 5135 PBMP_PORT_ITER(unit, port) { 5136 BCM_IF_ERROR_RETURN 5137 (_bcm_td_cosq_index_resolve(unit, port, -1, 5138 _BCM_TD_COSQ_INDEX_STYLE_WRED, NULL, 5139 NULL, &numq)); 5140 for (cosq = 0; cosq < numq; cosq++) { 5141 BCM_IF_ERROR_RETURN 5142 (_bcm_td_cosq_wred_set(unit, port, cosq, flags, 0, 0, 0, 0, 5143 FALSE)); 5144 } 5145 } 5146 5147 return BCM_E_NONE; 5148 } 5149 5150 int 5151 bcm_td_cosq_discard_get(int unit, uint32 *flags) 5152 { 5153 bcm_port_t port; 5154 5155 PBMP_PORT_ITER(unit, port) { 5156 *flags = 0; 5157 /* use setting from hardware cosq index 0 of the first port */ 5158 return _bcm_td_cosq_wred_get(unit, port, 0, flags, NULL, NULL, NULL, 5159 NULL); 5160 } 5161 5162 return BCM_E_NOT_FOUND; 5163 } 5164 5165 /* 5166 * Function: 5167 * bcm_td_cosq_discard_port_set 5168 * Purpose: 5169 * Configure port WRED setting 5170 * Parameters: 5171 * unit - (IN) unit number 5172 * port - (IN) port number or GPORT identifier 5173 * cosq - (IN) COS queue number 5174 * color - (IN) 5175 * drop_start - (IN) 5176 * drop_slot - (IN) 5177 * average_time - (IN) 5178 * Returns: 5179 * BCM_E_XXX 5180 * Notes: 5181 * If port is any form of local port, cosq is the hardware queue index. 5182 */ 5183 int 5184 bcm_td_cosq_discard_port_set(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 5185 uint32 color, int drop_start, int drop_slope, 5186 int average_time) 5187 { 5188 bcm_port_t local_port; 5189 bcm_pbmp_t pbmp; 5190 int gain; 5191 uint32 min_thresh, max_thresh, shared_limit; 5192 uint32 rval, bits; 5193 int numq, i; 5194 5195 if (drop_start < 0 || drop_start > 100 || 5196 drop_slope < 0 || drop_slope > 90) { 5197 return BCM_E_PARAM; 5198 } 5199 5200 /* 5201 * average queue size is reculated every 4us, the formula is 5202 * avg_qsize(t + 1) = 5203 * avg_qsize(t) + (cur_qsize - avg_qsize(t)) / (2 ** gain) 5204 * gain = log2(average_time / 4) 5205 */ 5206 bits = (average_time / 4) & 0xffff; 5207 if (bits != 0) { 5208 bits |= bits >> 1; 5209 bits |= bits >> 2; 5210 bits |= bits >> 4; 5211 bits |= bits >> 8; 5212 gain = _shr_popcount(bits) - 1; 5213 } else { 5214 gain = 0; 5215 } 5216 5217 /* 5218 * per-port cell limit may be disabled. 5219 * per-port per-cos cell limit may be set to use dynamic method. 5220 * therefore drop_start percentage is based on per-device total shared 5221 * cells. 5222 */ 5223 BCM_IF_ERROR_RETURN(READ_OP_BUFFER_SHARED_LIMIT_CELLr(unit, &rval)); 5224 shared_limit = soc_reg_field_get(unit, OP_BUFFER_SHARED_LIMIT_CELLr, 5225 rval, OP_BUFFER_SHARED_LIMIT_CELLf); 5226 min_thresh = drop_start * shared_limit / 100; 5227 5228 /* Calculate the max threshold. For a given slope (angle in 5229 * degrees), determine how many packets are in the range from 5230 * 0% drop probability to 100% drop probability. Add that 5231 * number to the min_treshold to the the max_threshold. 5232 */ 5233 max_thresh = min_thresh + _bcm_td_angle_to_cells(drop_slope); 5234 if (max_thresh > TD_CELL_FIELD_MAX) { 5235 max_thresh = TD_CELL_FIELD_MAX; 5236 } 5237 5238 if (BCM_GPORT_IS_SET(port)) { 5239 if (cosq == -1) { 5240 BCM_IF_ERROR_RETURN 5241 (_bcm_td_cosq_index_resolve(unit, port, cosq, 5242 _BCM_TD_COSQ_INDEX_STYLE_WRED, 5243 NULL, NULL, &numq)); 5244 cosq = 0; 5245 } else { 5246 numq = 1; 5247 } 5248 for (i = 0; i < numq; i++) { 5249 BCM_IF_ERROR_RETURN 5250 (_bcm_td_cosq_wred_set(unit, port, cosq + i, color, 5251 min_thresh, max_thresh, 100, gain, 5252 TRUE)); 5253 } 5254 } else { 5255 if (port == -1) { 5256 BCM_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit)); 5257 } else if (!SOC_PORT_VALID(unit, port)) { 5258 return BCM_E_PORT; 5259 } else { 5260 BCM_PBMP_PORT_SET(pbmp, port); 5261 } 5262 5263 BCM_PBMP_ITER(pbmp, local_port) { 5264 if (cosq == -1) { 5265 BCM_IF_ERROR_RETURN 5266 (_bcm_td_cosq_index_resolve(unit, local_port, cosq, 5267 _BCM_TD_COSQ_INDEX_STYLE_WRED, 5268 NULL, NULL, &numq)); 5269 cosq = 0; 5270 } else { 5271 numq = 1; 5272 } 5273 for (i = 0; i < numq; i++) { 5274 BCM_IF_ERROR_RETURN 5275 (_bcm_td_cosq_wred_set(unit, local_port, cosq + i, 5276 color, min_thresh, max_thresh, 100, 5277 gain, TRUE)); 5278 } 5279 } 5280 } 5281 5282 return BCM_E_NONE; 5283 } 5284 5285 /* 5286 * Function: 5287 * bcm_td_cosq_discard_port_get 5288 * Purpose: 5289 * Get port WRED setting 5290 * Parameters: 5291 * unit - (IN) unit number 5292 * port - (IN) port number or GPORT identifier 5293 * cosq - (IN) COS queue number 5294 * color - (OUT) 5295 * drop_start - (OUT) 5296 * drop_slot - (OUT) 5297 * average_time - (OUT) 5298 * Returns: 5299 * BCM_E_XXX 5300 * Notes: 5301 * If port is any form of local port, cosq is the hardware queue index. 5302 */ 5303 int 5304 bcm_td_cosq_discard_port_get(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 5305 uint32 color, int *drop_start, int *drop_slope, 5306 int *average_time) 5307 { 5308 bcm_port_t local_port; 5309 bcm_pbmp_t pbmp; 5310 int gain, drop_prob; 5311 uint32 min_thresh, max_thresh, shared_limit; 5312 uint32 rval; 5313 5314 if (drop_start == NULL || drop_slope == NULL || average_time == NULL) { 5315 return BCM_E_PARAM; 5316 } 5317 5318 if (BCM_GPORT_IS_SET(port)) { 5319 local_port = port; 5320 } else { 5321 if (port == -1) { 5322 BCM_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit)); 5323 } else if (!SOC_PORT_VALID(unit, port)) { 5324 return BCM_E_PORT; 5325 } else { 5326 BCM_PBMP_PORT_SET(pbmp, port); 5327 } 5328 BCM_PBMP_ITER(pbmp, local_port) { 5329 break; 5330 } 5331 } 5332 5333 BCM_IF_ERROR_RETURN 5334 (_bcm_td_cosq_wred_get(unit, local_port, cosq == -1 ? 0 : cosq, 5335 &color, &min_thresh, &max_thresh, &drop_prob, 5336 &gain)); 5337 5338 /* 5339 * average queue size is reculated every 4us, the formula is 5340 * avg_qsize(t + 1) = 5341 * avg_qsize(t) + (cur_qsize - avg_qsize(t)) / (2 ** gain) 5342 */ 5343 *average_time = (1 << gain) * 4; 5344 5345 /* 5346 * per-port cell limit may be disabled. 5347 * per-port per-cos cell limit may be set to use dynamic method. 5348 * therefore drop_start percentage is based on per-device total shared 5349 * cells. 5350 */ 5351 BCM_IF_ERROR_RETURN(READ_OP_BUFFER_SHARED_LIMIT_CELLr(unit, &rval)); 5352 shared_limit = soc_reg_field_get(unit, OP_BUFFER_SHARED_LIMIT_CELLr, 5353 rval, OP_BUFFER_SHARED_LIMIT_CELLf); 5354 if (min_thresh > shared_limit) { 5355 min_thresh = shared_limit; 5356 } 5357 5358 if (max_thresh > shared_limit) { 5359 max_thresh = shared_limit; 5360 } 5361 5362 *drop_start = min_thresh * 100 / shared_limit; 5363 5364 /* Calculate the slope using the min and max threshold. 5365 * The angle is calculated knowing drop probability at min 5366 * threshold is 0% and drop probability at max threshold is 100%. 5367 */ 5368 *drop_slope = _bcm_td_cells_to_angle(max_thresh - min_thresh); 5369 5370 return BCM_E_NONE; 5371 } 5372 5373 int 5374 bcm_td_cosq_stat_set(int unit, bcm_gport_t port, bcm_cos_queue_t cosq, 5375 bcm_cosq_stat_t stat, uint64 value) 5376 { 5377 soc_info_t *si; 5378 _bcm_td_cosq_node_t *node; 5379 bcm_port_t local_port; 5380 int startq, numq, i; 5381 5382 si = &SOC_INFO(unit); 5383 5384 switch (stat) { 5385 case bcmCosqStatDroppedPackets: 5386 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port)) { 5387 BCM_IF_ERROR_RETURN 5388 (_bcm_td_cosq_index_resolve 5389 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_UCAST_DROP, 5390 &local_port, &startq, NULL)); 5391 BCM_IF_ERROR_RETURN 5392 (soc_counter_set(unit, local_port, 5393 SOC_COUNTER_NON_DMA_COSQ_DROP_PKT_UC, startq, 5394 value)); 5395 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(port)) { 5396 BCM_IF_ERROR_RETURN 5397 (_bcm_td_cosq_index_resolve 5398 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_MCAST_QUEUE, 5399 &local_port, &startq, NULL)); 5400 BCM_IF_ERROR_RETURN 5401 (soc_counter_set(unit, local_port, 5402 SOC_COUNTER_NON_DMA_COSQ_DROP_PKT, startq, 5403 value)); 5404 } else { 5405 BCM_IF_ERROR_RETURN 5406 (_bcm_td_cosq_index_resolve 5407 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_MCAST_QUEUE, 5408 &local_port, &startq, &numq)); 5409 if (!IS_CPU_PORT(unit, local_port) && cosq != BCM_COS_INVALID) { 5410 return BCM_E_PARAM; 5411 } 5412 if (cosq == BCM_COS_INVALID) { 5413 numq = 1; 5414 } 5415 for (i = 0; i < numq; i++) { 5416 BCM_IF_ERROR_RETURN 5417 (soc_counter_set(unit, local_port, 5418 SOC_COUNTER_NON_DMA_COSQ_DROP_PKT, 5419 startq + i, value)); 5420 } 5421 if (si->port_num_uc_cosq[local_port] > 0) { 5422 BCM_IF_ERROR_RETURN 5423 (_bcm_td_cosq_index_resolve 5424 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_UCAST_DROP, 5425 &local_port, &startq, &numq)); 5426 if (cosq == BCM_COS_INVALID) { 5427 numq = 1; 5428 } 5429 for (i = 0; i < numq; i++) { 5430 BCM_IF_ERROR_RETURN 5431 (soc_counter_set(unit, local_port, 5432 SOC_COUNTER_NON_DMA_COSQ_DROP_PKT_UC, 5433 startq + i, value)); 5434 } 5435 } 5436 } 5437 break; 5438 case bcmCosqStatDroppedBytes: 5439 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port)) { 5440 BCM_IF_ERROR_RETURN 5441 (_bcm_td_cosq_index_resolve 5442 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_UCAST_DROP, 5443 &local_port, &startq, NULL)); 5444 BCM_IF_ERROR_RETURN 5445 (soc_counter_set(unit, local_port, 5446 SOC_COUNTER_NON_DMA_COSQ_DROP_BYTE_UC, startq, 5447 value)); 5448 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(port)) { 5449 BCM_IF_ERROR_RETURN 5450 (_bcm_td_cosq_index_resolve 5451 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_MCAST_QUEUE, 5452 &local_port, &startq, NULL)); 5453 BCM_IF_ERROR_RETURN 5454 (soc_counter_set(unit, local_port, 5455 SOC_COUNTER_NON_DMA_COSQ_DROP_BYTE, startq, 5456 value)); 5457 } else { 5458 BCM_IF_ERROR_RETURN 5459 (_bcm_td_cosq_index_resolve 5460 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_MCAST_QUEUE, 5461 &local_port, &startq, &numq)); 5462 if (!IS_CPU_PORT(unit, local_port) && cosq != BCM_COS_INVALID) { 5463 return BCM_E_PARAM; 5464 } 5465 if (cosq == BCM_COS_INVALID) { 5466 numq = 1; 5467 } 5468 for (i = 0; i < numq; i++) { 5469 BCM_IF_ERROR_RETURN 5470 (soc_counter_set(unit, local_port, 5471 SOC_COUNTER_NON_DMA_COSQ_DROP_BYTE, 5472 startq + i, value)); 5473 } 5474 if (si->port_num_uc_cosq[local_port] > 0) { 5475 BCM_IF_ERROR_RETURN 5476 (_bcm_td_cosq_index_resolve 5477 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_UCAST_DROP, 5478 &local_port, &startq, &numq)); 5479 if (cosq == BCM_COS_INVALID) { 5480 numq = 1; 5481 } 5482 for (i = 0; i < numq; i++) { 5483 BCM_IF_ERROR_RETURN 5484 (soc_counter_set(unit, local_port, 5485 SOC_COUNTER_NON_DMA_COSQ_DROP_BYTE_UC, 5486 startq + i, value)); 5487 } 5488 } 5489 } 5490 break; 5491 case bcmCosqStatYellowCongestionDroppedPackets: 5492 if (cosq != BCM_COS_INVALID) { 5493 return BCM_E_UNAVAIL; 5494 } 5495 BCM_IF_ERROR_RETURN 5496 (_bcm_td_cosq_localport_resolve(unit, port, &local_port)); 5497 BCM_IF_ERROR_RETURN 5498 (soc_counter_set(unit, local_port, 5499 SOC_COUNTER_NON_DMA_PORT_DROP_PKT_YELLOW, 0, 5500 value)); 5501 break; 5502 case bcmCosqStatRedCongestionDroppedPackets: 5503 if (cosq != BCM_COS_INVALID) { 5504 return BCM_E_UNAVAIL; 5505 } 5506 BCM_IF_ERROR_RETURN 5507 (_bcm_td_cosq_localport_resolve(unit, port, &local_port)); 5508 BCM_IF_ERROR_RETURN 5509 (soc_counter_set(unit, local_port, 5510 SOC_COUNTER_NON_DMA_PORT_DROP_PKT_RED, 0, 5511 value)); 5512 break; 5513 case bcmCosqStatGreenDiscardDroppedPackets: 5514 if (cosq != BCM_COS_INVALID) { 5515 return BCM_E_UNAVAIL; 5516 } 5517 BCM_IF_ERROR_RETURN 5518 (_bcm_td_cosq_localport_resolve(unit, port, &local_port)); 5519 BCM_IF_ERROR_RETURN 5520 (soc_counter_set(unit, local_port, 5521 SOC_COUNTER_NON_DMA_PORT_WRED_PKT_GREEN, 0, 5522 value)); 5523 break; 5524 case bcmCosqStatYellowDiscardDroppedPackets: 5525 if (cosq != BCM_COS_INVALID) { 5526 return BCM_E_UNAVAIL; 5527 } 5528 BCM_IF_ERROR_RETURN 5529 (_bcm_td_cosq_localport_resolve(unit, port, &local_port)); 5530 BCM_IF_ERROR_RETURN 5531 (soc_counter_set(unit, local_port, 5532 SOC_COUNTER_NON_DMA_PORT_WRED_PKT_YELLOW, 0, 5533 value)); 5534 break; 5535 case bcmCosqStatRedDiscardDroppedPackets: 5536 if (cosq != BCM_COS_INVALID) { 5537 return BCM_E_UNAVAIL; 5538 } 5539 BCM_IF_ERROR_RETURN 5540 (_bcm_td_cosq_localport_resolve(unit, port, &local_port)); 5541 BCM_IF_ERROR_RETURN 5542 (soc_counter_set(unit, local_port, 5543 SOC_COUNTER_NON_DMA_PORT_WRED_PKT_RED, 0, value)); 5544 break; 5545 case bcmCosqStatOutPackets: 5546 if (BCM_GPORT_IS_SCHEDULER(port)) { 5547 BCM_IF_ERROR_RETURN 5548 (_bcm_td_cosq_node_get(unit, port, NULL, 5549 &local_port, NULL, &node)); 5550 BCM_IF_ERROR_RETURN 5551 (_bcm_td_cosq_child_node_at_input(node, cosq, &node)); 5552 port = node->gport; 5553 if (BCM_GPORT_IS_SCHEDULER(port)) { 5554 /* Not support more than one-layer scheduler node analysis*/ 5555 return BCM_E_PARAM; 5556 } 5557 } 5558 5559 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port)) { 5560 if (BCM_GPORT_UCAST_QUEUE_GROUP_QID_GET(port) < 5561 _BCM_TD_NUM_UCAST_QUEUE_GROUP) { /* regular ucast queue */ 5562 BCM_IF_ERROR_RETURN 5563 (_bcm_td_cosq_index_resolve 5564 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_UCAST_QUEUE, 5565 &local_port, &startq, NULL)); 5566 BCM_IF_ERROR_RETURN 5567 (soc_counter_set(unit, local_port, 5568 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT_UC, 5569 startq, value)); 5570 } else { /* extended ucast queue */ 5571 BCM_IF_ERROR_RETURN 5572 (_bcm_td_cosq_index_resolve 5573 (unit, port, cosq, 5574 _BCM_TD_COSQ_INDEX_STYLE_EXT_UCAST_QUEUE, 5575 NULL, &startq, &numq)); 5576 for (i = 0; i < numq; i++) { 5577 BCM_IF_ERROR_RETURN 5578 (_bcm_td_cosq_index_resolve 5579 (unit, port, cosq < 0 ? i : cosq, 5580 _BCM_TD_COSQ_INDEX_STYLE_EXT_UCAST_QUEUE, 5581 &local_port, &startq, NULL)); 5582 BCM_IF_ERROR_RETURN 5583 (soc_counter_set 5584 (unit, local_port, 5585 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT_EXT, 5586 startq, value)); 5587 } 5588 } 5589 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(port)) { 5590 BCM_IF_ERROR_RETURN 5591 (_bcm_td_cosq_index_resolve 5592 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_MCAST_QUEUE, 5593 &local_port, &startq, NULL)); 5594 BCM_IF_ERROR_RETURN 5595 (soc_counter_set(unit, local_port, 5596 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT, startq, 5597 value)); 5598 } else { 5599 if (cosq < BCM_COS_INVALID) { 5600 return BCM_E_PARAM; 5601 } 5602 5603 BCM_IF_ERROR_RETURN 5604 (_bcm_td_cosq_localport_resolve(unit, port, &local_port)); 5605 if (cosq == BCM_COS_INVALID) { 5606 /* UC queue */ 5607 for (i = 0; i < si->port_num_uc_cosq[local_port]; i++) { 5608 BCM_IF_ERROR_RETURN 5609 (soc_counter_set(unit, local_port, 5610 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT_UC, 5611 i, value)); 5612 } 5613 /* MC queue */ 5614 for (i = 0; i < si->port_num_cosq[local_port]; i++) { 5615 BCM_IF_ERROR_RETURN 5616 (soc_counter_set(unit, local_port, 5617 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT, 5618 i, value)); 5619 } 5620 } else { 5621 /* 5622 * cosq=0 for ucast queue 0 + mcast queue 0 5623 * cosq=1 for ucast queue 1 + mcast queue 1 5624 * cosq=2 for ucast queue 2 + mcast queue 2 5625 * cosq=3 for ucast queue 3 + mcast queue 3 5626 * cosq=4 for ucast queue 4 5627 * cosq=5 for ucast queue 5 5628 * cosq=6 for ucast queue 6 5629 * cosq=7 for ucast queue 7 5630 * cosq=8 for unicast SC queue + multicast SC/QM queue 5631 * cosq=9 for unicast QM queue. 5632 */ 5633 if (IS_CPU_PORT(unit, local_port) || 5634 IS_LB_PORT(unit, local_port)) { 5635 if (cosq >= (si->port_num_cosq[local_port])) { 5636 return BCM_E_PARAM; 5637 } 5638 } else if (cosq >= (si->port_num_uc_cosq[local_port])){ 5639 return BCM_E_PARAM; 5640 } 5641 5642 if (IS_CPU_PORT(unit, local_port) || 5643 IS_LB_PORT(unit, local_port)) { 5644 BCM_IF_ERROR_RETURN 5645 (soc_counter_set(unit, local_port, 5646 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT, 5647 cosq, value)); 5648 } else { 5649 /* UC queue */ 5650 BCM_IF_ERROR_RETURN 5651 (soc_counter_set(unit, local_port, 5652 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT_UC, 5653 cosq, value)); 5654 /* MC queue */ 5655 if ((cosq < (si->port_num_cosq[local_port] - 1)) || 5656 (cosq == 8)) { 5657 cosq = (cosq == 8) ? 4 : cosq; 5658 BCM_IF_ERROR_RETURN 5659 (soc_counter_set(unit, local_port, 5660 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT, 5661 cosq, value)); 5662 } 5663 } 5664 } 5665 } 5666 break; 5667 case bcmCosqStatOutBytes: 5668 if (BCM_GPORT_IS_SCHEDULER(port)) { 5669 BCM_IF_ERROR_RETURN 5670 (_bcm_td_cosq_node_get(unit, port, NULL, 5671 &local_port, NULL, &node)); 5672 BCM_IF_ERROR_RETURN 5673 (_bcm_td_cosq_child_node_at_input(node, cosq, &node)); 5674 port = node->gport; 5675 if (BCM_GPORT_IS_SCHEDULER(port)) { 5676 /* Not support more than one-layer scheduler node analysis*/ 5677 return BCM_E_PARAM; 5678 } 5679 } 5680 5681 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port)) { 5682 if (BCM_GPORT_UCAST_QUEUE_GROUP_QID_GET(port) < 5683 _BCM_TD_NUM_UCAST_QUEUE_GROUP) { /* regular ucast queue */ 5684 BCM_IF_ERROR_RETURN 5685 (_bcm_td_cosq_index_resolve 5686 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_UCAST_QUEUE, 5687 &local_port, &startq, NULL)); 5688 BCM_IF_ERROR_RETURN 5689 (soc_counter_set(unit, local_port, 5690 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE_UC, 5691 startq, value)); 5692 } else { /* extended ucast queue */ 5693 BCM_IF_ERROR_RETURN 5694 (_bcm_td_cosq_index_resolve 5695 (unit, port, cosq, 5696 _BCM_TD_COSQ_INDEX_STYLE_EXT_UCAST_QUEUE, 5697 NULL, NULL, &numq)); 5698 for (i = 0; i < numq; i++) { 5699 BCM_IF_ERROR_RETURN 5700 (_bcm_td_cosq_index_resolve 5701 (unit, port, cosq < 0 ? i : cosq, 5702 _BCM_TD_COSQ_INDEX_STYLE_EXT_UCAST_QUEUE, 5703 &local_port, &startq, NULL)); 5704 BCM_IF_ERROR_RETURN 5705 (soc_counter_set 5706 (unit, local_port, 5707 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE_EXT, 5708 startq, value)); 5709 } 5710 } 5711 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(port)) { 5712 BCM_IF_ERROR_RETURN 5713 (_bcm_td_cosq_index_resolve 5714 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_MCAST_QUEUE, 5715 &local_port, &startq, NULL)); 5716 BCM_IF_ERROR_RETURN 5717 (soc_counter_set(unit, local_port, 5718 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE, startq, 5719 value)); 5720 } else { 5721 if (cosq < BCM_COS_INVALID) { 5722 return BCM_E_PARAM; 5723 } 5724 5725 BCM_IF_ERROR_RETURN 5726 (_bcm_td_cosq_localport_resolve(unit, port, &local_port)); 5727 if (cosq == BCM_COS_INVALID) { 5728 /* UC queue */ 5729 for (i = 0; i < si->port_num_uc_cosq[local_port]; i++) { 5730 BCM_IF_ERROR_RETURN 5731 (soc_counter_set(unit, local_port, 5732 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE_UC, 5733 i, value)); 5734 } 5735 /* MC queue */ 5736 for (i = 0; i < si->port_num_cosq[local_port]; i++) { 5737 BCM_IF_ERROR_RETURN 5738 (soc_counter_set(unit, local_port, 5739 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE, 5740 i, value)); 5741 } 5742 } else { 5743 /* 5744 * cosq=0 for ucast queue 0 + mcast queue 0 5745 * cosq=1 for ucast queue 1 + mcast queue 1 5746 * cosq=2 for ucast queue 2 + mcast queue 2 5747 * cosq=3 for ucast queue 3 + mcast queue 3 5748 * cosq=4 for ucast queue 4 5749 * cosq=5 for ucast queue 5 5750 * cosq=6 for ucast queue 6 5751 * cosq=7 for ucast queue 7 5752 * cosq=8 for unicast SC queue + multicast SC/QM queue 5753 * cosq=9 for unicast QM queue. 5754 */ 5755 if (IS_CPU_PORT(unit, local_port) || 5756 IS_LB_PORT(unit, local_port)) { 5757 if (cosq >= (si->port_num_cosq[local_port])) { 5758 return BCM_E_PARAM; 5759 } 5760 } else if (cosq >= (si->port_num_uc_cosq[local_port])){ 5761 return BCM_E_PARAM; 5762 } 5763 5764 if (IS_CPU_PORT(unit, local_port) || 5765 IS_LB_PORT(unit, local_port)) { 5766 BCM_IF_ERROR_RETURN 5767 (soc_counter_set(unit, local_port, 5768 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE, 5769 cosq, value)); 5770 } else { 5771 /* UC queue */ 5772 BCM_IF_ERROR_RETURN 5773 (soc_counter_set(unit, local_port, 5774 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE_UC, 5775 cosq, value)); 5776 /* MC queue */ 5777 if ((cosq < (si->port_num_cosq[local_port] - 1)) || 5778 (cosq == 8)) { 5779 cosq = (cosq == 8) ? 4 : cosq; 5780 BCM_IF_ERROR_RETURN 5781 (soc_counter_set(unit, local_port, 5782 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE, 5783 cosq, value)); 5784 } 5785 } 5786 } 5787 } 5788 break; 5789 case bcmCosqStatIeee8021CnCpTransmittedCnms: 5790 BCM_IF_ERROR_RETURN 5791 (_bcm_td_cosq_index_resolve 5792 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_UCAST_QUEUE, 5793 &local_port, NULL, NULL)); 5794 BCM_IF_ERROR_RETURN 5795 (bcm_td_cosq_congestion_queue_get(unit, port, cosq, &startq)); 5796 5797 BCM_IF_ERROR_RETURN 5798 (soc_counter_set(unit, local_port, 5799 SOC_COUNTER_NON_DMA_MMU_QCN_CNM, startq, value)); 5800 break; 5801 default: 5802 return BCM_E_PARAM; 5803 } 5804 5805 return BCM_E_NONE; 5806 } 5807 5808 int 5809 bcm_td_cosq_stat_get(int unit, bcm_port_t port, bcm_cos_queue_t cosq, 5810 bcm_cosq_stat_t stat, int sync_mode, uint64 *value) 5811 { 5812 soc_info_t *si; 5813 _bcm_td_cosq_node_t *node; 5814 bcm_port_t local_port; 5815 int startq, numq, i, start_hw_index, end_hw_index; 5816 uint64 sum, value64; 5817 int (*counter_get) (int , soc_port_t , soc_reg_t , int , uint64 *); 5818 5819 if (value == NULL) { 5820 return BCM_E_PARAM; 5821 } 5822 5823 /* 5824 * if sync-mode is set, update the software cached counter value, 5825 * with the hardware count and then retrieve the count. 5826 * else return the software cache counter value. 5827 */ 5828 counter_get = (sync_mode == 1)? soc_counter_sync_get: soc_counter_get; 5829 5830 si = &SOC_INFO(unit); 5831 5832 switch (stat) { 5833 case bcmCosqStatDroppedPackets: 5834 COMPILER_64_ZERO(sum); 5835 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port)) { 5836 BCM_IF_ERROR_RETURN 5837 (_bcm_td_cosq_index_resolve 5838 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_UCAST_DROP, 5839 &local_port, &startq, &numq)); 5840 for (i = 0; i < numq; i++) { 5841 BCM_IF_ERROR_RETURN 5842 (counter_get(unit, local_port, 5843 SOC_COUNTER_NON_DMA_COSQ_DROP_PKT_UC, 5844 startq + i, &value64)); 5845 COMPILER_64_ADD_64(sum, value64); 5846 } 5847 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(port)) { 5848 BCM_IF_ERROR_RETURN 5849 (_bcm_td_cosq_index_resolve 5850 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_MCAST_QUEUE, 5851 &local_port, &startq, &numq)); 5852 for (i = 0; i < numq; i++) { 5853 BCM_IF_ERROR_RETURN 5854 (counter_get(unit, local_port, 5855 SOC_COUNTER_NON_DMA_COSQ_DROP_PKT, 5856 startq + i, &value64)); 5857 COMPILER_64_ADD_64(sum, value64); 5858 } 5859 } else { 5860 BCM_IF_ERROR_RETURN 5861 (_bcm_td_cosq_index_resolve 5862 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_MCAST_QUEUE, 5863 &local_port, &startq, &numq)); 5864 if (!IS_CPU_PORT(unit, local_port) && cosq != BCM_COS_INVALID) { 5865 return BCM_E_PARAM; 5866 } 5867 for (i = 0; i < numq; i++) { 5868 BCM_IF_ERROR_RETURN 5869 (counter_get(unit, local_port, 5870 SOC_COUNTER_NON_DMA_COSQ_DROP_PKT, 5871 startq + i, &value64)); 5872 COMPILER_64_ADD_64(sum, value64); 5873 } 5874 if (si->port_num_uc_cosq[local_port] > 0) { 5875 BCM_IF_ERROR_RETURN 5876 (_bcm_td_cosq_index_resolve 5877 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_UCAST_DROP, 5878 &local_port, &startq, &numq)); 5879 for (i = 0; i < numq; i++) { 5880 BCM_IF_ERROR_RETURN 5881 (counter_get(unit, local_port, 5882 SOC_COUNTER_NON_DMA_COSQ_DROP_PKT_UC, 5883 startq + i, &value64)); 5884 COMPILER_64_ADD_64(sum, value64); 5885 } 5886 } 5887 } 5888 *value = sum; 5889 break; 5890 case bcmCosqStatDroppedBytes: 5891 COMPILER_64_ZERO(sum); 5892 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port)) { 5893 BCM_IF_ERROR_RETURN 5894 (_bcm_td_cosq_index_resolve 5895 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_UCAST_DROP, 5896 &local_port, &startq, &numq)); 5897 for (i = 0; i < numq; i++) { 5898 BCM_IF_ERROR_RETURN 5899 (counter_get(unit, local_port, 5900 SOC_COUNTER_NON_DMA_COSQ_DROP_BYTE_UC, 5901 startq + i, &value64)); 5902 COMPILER_64_ADD_64(sum, value64); 5903 } 5904 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(port)) { 5905 BCM_IF_ERROR_RETURN 5906 (_bcm_td_cosq_index_resolve 5907 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_MCAST_QUEUE, 5908 &local_port, &startq, &numq)); 5909 for (i = 0; i < numq; i++) { 5910 BCM_IF_ERROR_RETURN 5911 (counter_get(unit, local_port, 5912 SOC_COUNTER_NON_DMA_COSQ_DROP_BYTE, 5913 startq + i, &value64)); 5914 COMPILER_64_ADD_64(sum, value64); 5915 } 5916 } else { 5917 BCM_IF_ERROR_RETURN 5918 (_bcm_td_cosq_index_resolve 5919 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_MCAST_QUEUE, 5920 &local_port, &startq, &numq)); 5921 if (!IS_CPU_PORT(unit, local_port) && cosq != BCM_COS_INVALID) { 5922 return BCM_E_PARAM; 5923 } 5924 for (i = 0; i < numq; i++) { 5925 BCM_IF_ERROR_RETURN 5926 (counter_get(unit, local_port, 5927 SOC_COUNTER_NON_DMA_COSQ_DROP_BYTE, 5928 startq + i, &value64)); 5929 COMPILER_64_ADD_64(sum, value64); 5930 } 5931 if (si->port_num_uc_cosq[local_port] > 0) { 5932 BCM_IF_ERROR_RETURN 5933 (_bcm_td_cosq_index_resolve 5934 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_UCAST_DROP, 5935 &local_port, &startq, &numq)); 5936 for (i = 0; i < numq; i++) { 5937 BCM_IF_ERROR_RETURN 5938 (counter_get(unit, local_port, 5939 SOC_COUNTER_NON_DMA_COSQ_DROP_BYTE_UC, 5940 startq + i, &value64)); 5941 COMPILER_64_ADD_64(sum, value64); 5942 } 5943 } 5944 } 5945 *value = sum; 5946 break; 5947 case bcmCosqStatYellowCongestionDroppedPackets: 5948 if (cosq != BCM_COS_INVALID) { 5949 return BCM_E_UNAVAIL; 5950 } 5951 BCM_IF_ERROR_RETURN 5952 (_bcm_td_cosq_localport_resolve(unit, port, &local_port)); 5953 BCM_IF_ERROR_RETURN 5954 (counter_get(unit, local_port, 5955 SOC_COUNTER_NON_DMA_PORT_DROP_PKT_YELLOW, 0, 5956 value)); 5957 break; 5958 case bcmCosqStatRedCongestionDroppedPackets: 5959 if (cosq != BCM_COS_INVALID) { 5960 return BCM_E_UNAVAIL; 5961 } 5962 BCM_IF_ERROR_RETURN 5963 (_bcm_td_cosq_localport_resolve(unit, port, &local_port)); 5964 BCM_IF_ERROR_RETURN 5965 (counter_get(unit, local_port, 5966 SOC_COUNTER_NON_DMA_PORT_DROP_PKT_RED, 0, 5967 value)); 5968 break; 5969 case bcmCosqStatGreenDiscardDroppedPackets: 5970 if (cosq != BCM_COS_INVALID) { 5971 return BCM_E_UNAVAIL; 5972 } 5973 BCM_IF_ERROR_RETURN 5974 (_bcm_td_cosq_localport_resolve(unit, port, &local_port)); 5975 BCM_IF_ERROR_RETURN 5976 (counter_get(unit, local_port, 5977 SOC_COUNTER_NON_DMA_PORT_WRED_PKT_GREEN, 0, 5978 value)); 5979 break; 5980 case bcmCosqStatYellowDiscardDroppedPackets: 5981 if (cosq != BCM_COS_INVALID) { 5982 return BCM_E_UNAVAIL; 5983 } 5984 BCM_IF_ERROR_RETURN 5985 (_bcm_td_cosq_localport_resolve(unit, port, &local_port)); 5986 BCM_IF_ERROR_RETURN 5987 (counter_get(unit, local_port, 5988 SOC_COUNTER_NON_DMA_PORT_WRED_PKT_YELLOW, 0, 5989 value)); 5990 break; 5991 case bcmCosqStatRedDiscardDroppedPackets: 5992 if (cosq != BCM_COS_INVALID) { 5993 return BCM_E_UNAVAIL; 5994 } 5995 BCM_IF_ERROR_RETURN 5996 (_bcm_td_cosq_localport_resolve(unit, port, &local_port)); 5997 BCM_IF_ERROR_RETURN 5998 (counter_get(unit, local_port, 5999 SOC_COUNTER_NON_DMA_PORT_WRED_PKT_RED, 0, value)); 6000 break; 6001 case bcmCosqStatOutPackets: 6002 if (BCM_GPORT_IS_SCHEDULER(port)) { 6003 BCM_IF_ERROR_RETURN 6004 (_bcm_td_cosq_node_get(unit, port, NULL, 6005 &local_port, NULL, &node)); 6006 BCM_IF_ERROR_RETURN 6007 (_bcm_td_cosq_child_node_at_input(node, cosq, &node)); 6008 port = node->gport; 6009 if (BCM_GPORT_IS_SCHEDULER(port)) { 6010 /* Not support more than one-layer scheduler node analysis*/ 6011 return BCM_E_PARAM; 6012 } 6013 } 6014 6015 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port)) { 6016 if (BCM_GPORT_UCAST_QUEUE_GROUP_QID_GET(port) < 6017 _BCM_TD_NUM_UCAST_QUEUE_GROUP) { /* regular ucast queue */ 6018 BCM_IF_ERROR_RETURN 6019 (_bcm_td_cosq_index_resolve 6020 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_UCAST_QUEUE, 6021 &local_port, &startq, NULL)); 6022 BCM_IF_ERROR_RETURN 6023 (counter_get(unit, local_port, 6024 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT_UC, 6025 startq, value)); 6026 } else { /* extended ucast queue */ 6027 BCM_IF_ERROR_RETURN 6028 (_bcm_td_cosq_index_resolve 6029 (unit, port, cosq, 6030 _BCM_TD_COSQ_INDEX_STYLE_EXT_UCAST_QUEUE, 6031 NULL, NULL, &numq)); 6032 COMPILER_64_ZERO(sum); 6033 for (i = 0; i < numq; i++) { 6034 BCM_IF_ERROR_RETURN 6035 (_bcm_td_cosq_index_resolve 6036 (unit, port, cosq < 0 ? i : cosq, 6037 _BCM_TD_COSQ_INDEX_STYLE_EXT_UCAST_QUEUE, 6038 &local_port, &startq, NULL)); 6039 BCM_IF_ERROR_RETURN 6040 (counter_get 6041 (unit, local_port, 6042 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT_EXT, 6043 startq, &value64)); 6044 COMPILER_64_ADD_64(sum, value64); 6045 } 6046 *value = sum; 6047 } 6048 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(port)) { 6049 BCM_IF_ERROR_RETURN 6050 (_bcm_td_cosq_index_resolve 6051 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_MCAST_QUEUE, 6052 &local_port, &startq, NULL)); 6053 BCM_IF_ERROR_RETURN 6054 (counter_get(unit, local_port, 6055 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT, startq, 6056 value)); 6057 } else { 6058 if (cosq < BCM_COS_INVALID) { 6059 return BCM_E_PARAM; 6060 } 6061 6062 BCM_IF_ERROR_RETURN 6063 (_bcm_td_cosq_localport_resolve(unit, port, &local_port)); 6064 COMPILER_64_ZERO(sum); 6065 if (cosq == BCM_COS_INVALID) { 6066 /* UC queue */ 6067 for (i = 0; i < si->port_num_uc_cosq[local_port]; i++) { 6068 BCM_IF_ERROR_RETURN 6069 (counter_get(unit, local_port, 6070 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT_UC, 6071 i, &value64)); 6072 COMPILER_64_ADD_64(sum, value64); 6073 } 6074 /* MC queue */ 6075 for (i = 0; i < si->port_num_cosq[local_port]; i++) { 6076 BCM_IF_ERROR_RETURN 6077 (counter_get(unit, local_port, 6078 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT, 6079 i, &value64)); 6080 COMPILER_64_ADD_64(sum, value64); 6081 } 6082 } else { 6083 /* 6084 * cosq=0 for ucast queue 0 + mcast queue 0 6085 * cosq=1 for ucast queue 1 + mcast queue 1 6086 * cosq=2 for ucast queue 2 + mcast queue 2 6087 * cosq=3 for ucast queue 3 + mcast queue 3 6088 * cosq=4 for ucast queue 4 6089 * cosq=5 for ucast queue 5 6090 * cosq=6 for ucast queue 6 6091 * cosq=7 for ucast queue 7 6092 * cosq=8 for unicast SC queue + multicast SC/QM queue 6093 * cosq=9 for unicast QM queue. 6094 */ 6095 if (IS_CPU_PORT(unit, local_port) || 6096 IS_LB_PORT(unit, local_port)) { 6097 if (cosq >= (si->port_num_cosq[local_port])) { 6098 return BCM_E_PARAM; 6099 } 6100 } else if (cosq >= (si->port_num_uc_cosq[local_port])){ 6101 return BCM_E_PARAM; 6102 } 6103 6104 if (IS_CPU_PORT(unit, local_port) || 6105 IS_LB_PORT(unit, local_port)) { 6106 BCM_IF_ERROR_RETURN 6107 (counter_get(unit, local_port, 6108 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT, 6109 cosq, &value64)); 6110 COMPILER_64_ADD_64(sum, value64); 6111 } else { 6112 /* UC queue */ 6113 BCM_IF_ERROR_RETURN 6114 (counter_get(unit, local_port, 6115 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT_UC, 6116 cosq, &value64)); 6117 COMPILER_64_ADD_64(sum, value64); 6118 /* MC queue */ 6119 if ((cosq < (si->port_num_cosq[local_port] - 1)) || 6120 (cosq == 8)){ 6121 cosq = (cosq == 8) ? 4 : cosq; 6122 BCM_IF_ERROR_RETURN 6123 (counter_get(unit, local_port, 6124 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT, 6125 cosq, &value64)); 6126 COMPILER_64_ADD_64(sum, value64); 6127 } 6128 } 6129 } 6130 *value = sum; 6131 } 6132 break; 6133 case bcmCosqStatOutBytes: 6134 if (BCM_GPORT_IS_SCHEDULER(port)) { 6135 BCM_IF_ERROR_RETURN 6136 (_bcm_td_cosq_node_get(unit, port, NULL, 6137 &local_port, NULL, &node)); 6138 BCM_IF_ERROR_RETURN 6139 (_bcm_td_cosq_child_node_at_input(node, cosq, &node)); 6140 port = node->gport; 6141 if (BCM_GPORT_IS_SCHEDULER(port)) { 6142 /* Not support more than one-layer scheduler node analysis*/ 6143 return BCM_E_PARAM; 6144 } 6145 } 6146 6147 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(port)) { 6148 if (BCM_GPORT_UCAST_QUEUE_GROUP_QID_GET(port) < 6149 _BCM_TD_NUM_UCAST_QUEUE_GROUP) { /* regular ucast queue */ 6150 BCM_IF_ERROR_RETURN 6151 (_bcm_td_cosq_index_resolve 6152 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_UCAST_QUEUE, 6153 &local_port, &startq, NULL)); 6154 BCM_IF_ERROR_RETURN 6155 (counter_get(unit, local_port, 6156 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE_UC, 6157 startq, value)); 6158 } else { /* extended ucast queue */ 6159 BCM_IF_ERROR_RETURN 6160 (_bcm_td_cosq_index_resolve 6161 (unit, port, cosq, 6162 _BCM_TD_COSQ_INDEX_STYLE_EXT_UCAST_QUEUE, 6163 NULL, NULL, &numq)); 6164 COMPILER_64_ZERO(sum); 6165 for (i = 0; i < numq; i++) { 6166 BCM_IF_ERROR_RETURN 6167 (_bcm_td_cosq_index_resolve 6168 (unit, port, cosq < 0 ? i : cosq, 6169 _BCM_TD_COSQ_INDEX_STYLE_EXT_UCAST_QUEUE, 6170 &local_port, &startq, NULL)); 6171 BCM_IF_ERROR_RETURN 6172 (counter_get 6173 (unit, local_port, 6174 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE_EXT, 6175 startq, &value64)); 6176 COMPILER_64_ADD_64(sum, value64); 6177 } 6178 *value = sum; 6179 } 6180 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(port)) { 6181 BCM_IF_ERROR_RETURN 6182 (_bcm_td_cosq_index_resolve 6183 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_MCAST_QUEUE, 6184 &local_port, &startq, NULL)); 6185 BCM_IF_ERROR_RETURN 6186 (counter_get(unit, local_port, 6187 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE, startq, 6188 value)); 6189 } else { 6190 if (cosq < BCM_COS_INVALID) { 6191 return BCM_E_PARAM; 6192 } 6193 6194 BCM_IF_ERROR_RETURN 6195 (_bcm_td_cosq_localport_resolve(unit, port, &local_port)); 6196 COMPILER_64_ZERO(sum); 6197 if (cosq == BCM_COS_INVALID) { 6198 /* UC queue */ 6199 for (i = 0; i < si->port_num_uc_cosq[local_port]; i++) { 6200 BCM_IF_ERROR_RETURN 6201 (counter_get(unit, local_port, 6202 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE_UC, 6203 i, &value64)); 6204 COMPILER_64_ADD_64(sum, value64); 6205 } 6206 /* MC queue */ 6207 for (i = 0; i < si->port_num_cosq[local_port]; i++) { 6208 BCM_IF_ERROR_RETURN 6209 (counter_get(unit, local_port, 6210 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE, 6211 i, &value64)); 6212 COMPILER_64_ADD_64(sum, value64); 6213 } 6214 } else { 6215 /* 6216 * cosq=0 for ucast queue 0 + mcast queue 0 6217 * cosq=1 for ucast queue 1 + mcast queue 1 6218 * cosq=2 for ucast queue 2 + mcast queue 2 6219 * cosq=3 for ucast queue 3 + mcast queue 3 6220 * cosq=4 for ucast queue 4 6221 * cosq=5 for ucast queue 5 6222 * cosq=6 for ucast queue 6 6223 * cosq=7 for ucast queue 7 6224 * cosq=8 for unicast SC queue + multicast SC/QM queue 6225 * cosq=9 for unicast QM queue. 6226 */ 6227 if (IS_CPU_PORT(unit, local_port) || 6228 IS_LB_PORT(unit, local_port)) { 6229 if (cosq >= (si->port_num_cosq[local_port])) { 6230 return BCM_E_PARAM; 6231 } 6232 } else if (cosq >= (si->port_num_uc_cosq[local_port])){ 6233 return BCM_E_PARAM; 6234 } 6235 6236 if (IS_CPU_PORT(unit, local_port) || 6237 IS_LB_PORT(unit, local_port)) { 6238 BCM_IF_ERROR_RETURN 6239 (counter_get(unit, local_port, 6240 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE, 6241 cosq, &value64)); 6242 COMPILER_64_ADD_64(sum, value64); 6243 } else { 6244 /* UC queue */ 6245 BCM_IF_ERROR_RETURN 6246 (counter_get(unit, local_port, 6247 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE_UC, 6248 cosq, &value64)); 6249 COMPILER_64_ADD_64(sum, value64); 6250 /* MC queue */ 6251 if ((cosq < (si->port_num_cosq[local_port] - 1)) || 6252 (cosq == 8)){ 6253 cosq = (cosq == 8) ? 4 : cosq; 6254 BCM_IF_ERROR_RETURN 6255 (counter_get(unit, local_port, 6256 SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE, 6257 cosq, &value64)); 6258 COMPILER_64_ADD_64(sum, value64); 6259 } 6260 } 6261 } 6262 *value = sum; 6263 } 6264 break; 6265 case bcmCosqStatIeee8021CnCpTransmittedCnms: 6266 BCM_IF_ERROR_RETURN 6267 (_bcm_td_cosq_index_resolve 6268 (unit, port, cosq, _BCM_TD_COSQ_INDEX_STYLE_UCAST_QUEUE, 6269 &local_port, NULL, NULL)); 6270 BCM_IF_ERROR_RETURN 6271 (bcm_td_cosq_congestion_queue_get(unit, port, cosq, &startq)); 6272 BCM_IF_ERROR_RETURN 6273 (counter_get(unit, local_port, 6274 SOC_COUNTER_NON_DMA_MMU_QCN_CNM,startq, value)); 6275 break; 6276 case bcmCosqStatIngressPortPoolSharedBytesPeak: 6277 COMPILER_64_ZERO(sum); 6278 BCM_IF_ERROR_RETURN 6279 (_bcm_td_cosq_ingress_sp_get(unit, port, cosq, &start_hw_index, 6280 &end_hw_index)); 6281 BCM_IF_ERROR_RETURN(_bcm_td_cosq_localport_resolve(unit, port, 6282 &local_port)); 6283 for (i = start_hw_index; i <= end_hw_index; i++) { 6284 /* coverity[NEGATIVE_RETURNS: FALSE] */ 6285 BCM_IF_ERROR_RETURN 6286 (counter_get(unit, local_port, 6287 SOC_COUNTER_NON_DMA_POOL_PEAK, 6288 i, &value64)); 6289 COMPILER_64_ADD_64(sum, value64); 6290 } 6291 6292 COMPILER_64_UMUL_32(sum, _BCM_TD_BYTES_PER_CELL); 6293 *value = sum; 6294 break; 6295 case bcmCosqStatIngressPortPoolSharedBytesCurrent: 6296 BCM_IF_ERROR_RETURN 6297 (_bcm_td_cosq_ingress_sp_get(unit, port, cosq, &start_hw_index, 6298 &end_hw_index)); 6299 BCM_IF_ERROR_RETURN(_bcm_td_cosq_localport_resolve(unit, port, 6300 &local_port)); 6301 6302 COMPILER_64_ZERO(sum); 6303 for (i = start_hw_index; i <= end_hw_index; i++) { 6304 /* coverity[NEGATIVE_RETURNS: FALSE] */ 6305 BCM_IF_ERROR_RETURN 6306 (counter_get(unit, local_port, 6307 SOC_COUNTER_NON_DMA_POOL_CURRENT, 6308 i, &value64)); 6309 COMPILER_64_ADD_64(sum, value64); 6310 } 6311 6312 COMPILER_64_UMUL_32(sum, _BCM_TD_BYTES_PER_CELL); 6313 *value = sum; 6314 break; 6315 6316 default: 6317 return BCM_E_PARAM; 6318 } 6319 6320 return BCM_E_NONE; 6321 } 6322 6323 /* 6324 * Function: 6325 * _bcm_td_cosq_quantize_table_set 6326 * Purpose: 6327 * Generate quantized feedback lookup table 6328 * Parameters: 6329 * unit - (IN) unit number 6330 * profile_index - (IN) profile index 6331 * weight_code - (IN) weight encoding 6332 * set_point - (IN) queue size set point 6333 * active_offset - (OUT) most significant non-zero bit position 6334 * Returns: 6335 * BCM_E_XXX 6336 * Notes: 6337 * The formular to quantize feedback value is: 6338 * quantized_feedbad = celling(feedback / max_feedback * 63) 6339 * where max_feedback = (2 * cpW + 1) * cpQsp 6340 * cpW is feedback weight 6341 * cpQsp is queue size set point 6342 */ 6343 STATIC int 6344 _bcm_td_cosq_quantize_table_set(int unit, int profile_index, int weight_code, 6345 int set_point, int *active_offset) 6346 { 6347 int ref_count; 6348 int weight_x_4, feedback, max_feedback, quantized_feedback, shift; 6349 int base_index, index; 6350 6351 /* weight = 2 ** (weight_code - 2) e.g. 0 for 1/4, 1 for 1/2, ... */ 6352 weight_x_4 = 1 << weight_code; 6353 max_feedback = ((2 * weight_x_4 + 4) * set_point + 3) / 4; 6354 shift = 0; 6355 while ((max_feedback >> shift) > 127) { 6356 shift++; 6357 } 6358 6359 BCM_IF_ERROR_RETURN 6360 (soc_profile_reg_ref_count_get(unit, _bcm_td_feedback_profile[unit], 6361 profile_index, &ref_count)); 6362 6363 /* 6364 * Hardware use lookup table to find quantized feedback in order to avoid 6365 * division, use most significant 7-bit of feedback value as lookup table 6366 * index to find quantized_feedback value 6367 */ 6368 if (ref_count == 1) { 6369 base_index = profile_index << 7; 6370 for (index = 0; index < 128; index++) { 6371 feedback = index << shift; 6372 if (feedback > max_feedback) { 6373 quantized_feedback = 63; 6374 } else { 6375 quantized_feedback = (feedback * 63 + max_feedback - 1) / 6376 max_feedback; 6377 } 6378 BCM_IF_ERROR_RETURN 6379 (soc_mem_field32_modify(unit, MMU_QCN_QFBTBm, 6380 base_index + index, CPQ_QNTZFBf, 6381 quantized_feedback)); 6382 } 6383 } 6384 6385 *active_offset = shift + 6; 6386 6387 return BCM_E_NONE; 6388 } 6389 6390 STATIC int 6391 _bcm_td_cosq_sample_int_table_set(int unit, int min, int max, 6392 uint32 *profile_index) 6393 { 6394 mmu_qcn_sitb_entry_t sitb_entries[64]; 6395 void *entries[1]; 6396 int i, j, center, inc, value, index; 6397 6398 sal_memset(sitb_entries, 0, sizeof(sitb_entries)); 6399 entries[0] = &sitb_entries; 6400 for (i = 0; i < 8; i++) { 6401 center = max - (max - min) * i / 7; 6402 inc = (max - min) / 7 / 8; 6403 for (j = 0; j < 8; j++, inc = -inc) { 6404 index = i * 8 + j; 6405 value = center + (j + 1) / 2 * inc; 6406 if (value > 255) { 6407 value = 255; 6408 } else if (value < 1) { 6409 value = 1; 6410 } 6411 soc_mem_field32_set(unit, MMU_QCN_SITBm, &sitb_entries[index], 6412 CPQ_SIf, value); 6413 } 6414 } 6415 6416 return soc_profile_mem_add(unit, _bcm_td_sample_int_profile[unit], entries, 6417 64, (uint32 *)profile_index); 6418 } 6419 6420 /* 6421 * Function: 6422 * bcm_td_cosq_congestion_queue_set 6423 * Purpose: 6424 * Enable/Disable a cos queue as congestion managed queue 6425 * Parameters: 6426 * unit - (IN) unit number 6427 * port - (IN) port number or GPORT identifier 6428 * cosq - (IN) COS queue number 6429 * index - (IN) congestion managed queue index 6430 * Returns: 6431 * BCM_E_XXX 6432 */ 6433 int 6434 bcm_td_cosq_congestion_queue_set(int unit, bcm_port_t port, 6435 bcm_cos_queue_t cosq, int index) 6436 { 6437 soc_info_t *si; 6438 bcm_port_t local_port; 6439 int phy_port, mmu_port; 6440 uint32 rval; 6441 uint64 rval64, *rval64s[1]; 6442 mmu_qcn_enable_entry_t enable_entry; 6443 mmu_qcn_cpqcfg_entry_t cpqcfg_entry; 6444 int cosq_index, active_offset, count; 6445 uint32 profile_index, sample_profile_index; 6446 int weight_code, set_point; 6447 int qindex; 6448 6449 si = &SOC_INFO(unit); 6450 6451 if (cosq < 0 || cosq >= _bcm_td_num_cosq[unit]) { 6452 return BCM_E_PARAM; 6453 } 6454 6455 if (index < -1 || index > 1) { 6456 return BCM_E_PARAM; 6457 } 6458 6459 BCM_IF_ERROR_RETURN 6460 (_bcm_td_cosq_index_resolve(unit, port, cosq, 6461 _BCM_TD_COSQ_INDEX_STYLE_UCAST_QUEUE, 6462 &local_port, &qindex, NULL)); 6463 6464 phy_port = si->port_l2p_mapping[local_port]; 6465 mmu_port = si->port_p2m_mapping[phy_port]; 6466 BCM_IF_ERROR_RETURN(soc_mem_read(unit, MMU_QCN_ENABLEm, 6467 MEM_BLOCK_ANY, mmu_port, &enable_entry)); 6468 if (index == -1) { 6469 if (!soc_mem_field32_get(unit, MMU_QCN_ENABLEm, &enable_entry, 6470 _bcm_td_cpq_en_field[qindex])) { 6471 return BCM_E_NONE; 6472 } 6473 6474 index = soc_mem_field32_get(unit, MMU_QCN_ENABLEm, &enable_entry, 6475 _bcm_td_cpq_index_field[qindex]); 6476 soc_mem_field32_set(unit, MMU_QCN_ENABLEm, &enable_entry, 6477 _bcm_td_cpq_en_field[qindex], 0); 6478 BCM_IF_ERROR_RETURN 6479 (soc_mem_write(unit, MMU_QCN_ENABLEm, MEM_BLOCK_ANY, mmu_port, 6480 &enable_entry)); 6481 6482 /* Delete feedback parameter profile */ 6483 BCM_IF_ERROR_RETURN(soc_mem_read(unit, MMU_QCN_CPQCFGm, MEM_BLOCK_ANY, 6484 mmu_port, &cpqcfg_entry)); 6485 profile_index = 6486 soc_mem_field32_get(unit, MMU_QCN_CPQCFGm, &cpqcfg_entry, 6487 _bcm_td_eqtb_index_field[index]); 6488 BCM_IF_ERROR_RETURN 6489 (soc_profile_reg_delete(unit, _bcm_td_feedback_profile[unit], 6490 profile_index)); 6491 } else { 6492 count = sizeof(_bcm_td_cpq_en_field) / sizeof(_bcm_td_cpq_en_field[0]); 6493 for (cosq_index = 0; cosq_index < count; cosq_index++) { 6494 if (!soc_mem_field32_get(unit, MMU_QCN_ENABLEm, &enable_entry, 6495 _bcm_td_cpq_en_field[cosq_index])) { 6496 continue; 6497 } 6498 if (soc_mem_field32_get(unit, MMU_QCN_ENABLEm, &enable_entry, 6499 _bcm_td_cpq_index_field[cosq_index]) == 6500 index) { 6501 if (cosq_index == qindex) { 6502 return BCM_E_NONE; 6503 } else { 6504 return BCM_E_EXISTS; 6505 } 6506 } 6507 } 6508 6509 /* Use hardware reset value as default quantize setting */ 6510 weight_code = 3; 6511 set_point = 0x96; 6512 rval = 0; 6513 soc_reg_field_set(unit, MMU_QCN_CPQ_SEQr, &rval, CPWf, weight_code); 6514 soc_reg_field_set(unit, MMU_QCN_CPQ_SEQr, &rval, CPQEQf, set_point); 6515 COMPILER_64_SET(rval64, 0, rval); 6516 rval64s[0] = &rval64; 6517 BCM_IF_ERROR_RETURN 6518 (soc_profile_reg_add(unit, _bcm_td_feedback_profile[unit], 6519 rval64s, 1, (uint32 *)&profile_index)); 6520 6521 /* Update quantized feedback calculation lookup table */ 6522 BCM_IF_ERROR_RETURN 6523 (_bcm_td_cosq_quantize_table_set(unit, profile_index, weight_code, 6524 set_point, &active_offset)); 6525 6526 /* Pick some sample interval */ 6527 BCM_IF_ERROR_RETURN 6528 (_bcm_td_cosq_sample_int_table_set(unit, 13, 127, 6529 &sample_profile_index)); 6530 6531 BCM_IF_ERROR_RETURN(soc_mem_read(unit, MMU_QCN_CPQCFGm, MEM_BLOCK_ANY, 6532 mmu_port, &cpqcfg_entry)); 6533 soc_mem_field32_set(unit, MMU_QCN_CPQCFGm, &cpqcfg_entry, 6534 _bcm_td_act_offset_field[index], active_offset); 6535 soc_mem_field32_set(unit, MMU_QCN_CPQCFGm, &cpqcfg_entry, 6536 _bcm_td_eqtb_index_field[index], profile_index); 6537 soc_mem_field32_set(unit, MMU_QCN_CPQCFGm, &cpqcfg_entry, 6538 _bcm_td_sitb_sel_field[index], 6539 sample_profile_index); 6540 BCM_IF_ERROR_RETURN(soc_mem_write(unit, MMU_QCN_CPQCFGm, MEM_BLOCK_ANY, 6541 mmu_port, &cpqcfg_entry)); 6542 6543 soc_mem_field32_set(unit, MMU_QCN_ENABLEm, &enable_entry, 6544 _bcm_td_cpq_en_field[qindex], 1); 6545 soc_mem_field32_set(unit, MMU_QCN_ENABLEm, &enable_entry, 6546 _bcm_td_cpq_index_field[qindex], index); 6547 BCM_IF_ERROR_RETURN 6548 (soc_mem_write(unit, MMU_QCN_ENABLEm, MEM_BLOCK_ANY, mmu_port, 6549 &enable_entry)); 6550 } 6551 6552 /* Need to program ING_OUTER_DOT1P_MAPPING_TABLE to bypass the cosq */ 6553 6554 return BCM_E_NONE; 6555 } 6556 6557 /* 6558 * Function: 6559 * bcm_td_cosq_congestion_queue_get 6560 * Purpose: 6561 * Get congestion managed queue index of the specified cos queue 6562 * Parameters: 6563 * unit - (IN) unit number 6564 * port - (IN) port number or GPORT identifier 6565 * cosq - (IN) COS queue number 6566 * index - (OUT) congestion managed queue index 6567 * Returns: 6568 * BCM_E_XXX 6569 */ 6570 int 6571 bcm_td_cosq_congestion_queue_get(int unit, bcm_port_t port, 6572 bcm_cos_queue_t cosq, int *index) 6573 { 6574 soc_info_t *si; 6575 bcm_port_t local_port; 6576 int phy_port, mmu_port; 6577 mmu_qcn_enable_entry_t entry; 6578 int qindex; 6579 6580 si = &SOC_INFO(unit); 6581 6582 if (cosq < 0 || cosq >= _bcm_td_num_cosq[unit]) { 6583 return BCM_E_PARAM; 6584 } 6585 6586 if (index == NULL) { 6587 return BCM_E_PARAM; 6588 } 6589 6590 BCM_IF_ERROR_RETURN 6591 (_bcm_td_cosq_index_resolve(unit, port, cosq, 6592 _BCM_TD_COSQ_INDEX_STYLE_UCAST_QUEUE, 6593 &local_port, &qindex, NULL)); 6594 6595 phy_port = si->port_l2p_mapping[local_port]; 6596 mmu_port = si->port_p2m_mapping[phy_port]; 6597 BCM_IF_ERROR_RETURN 6598 (soc_mem_read(unit, MMU_QCN_ENABLEm, MEM_BLOCK_ANY, mmu_port, &entry)); 6599 if (soc_mem_field32_get(unit, MMU_QCN_ENABLEm, &entry, 6600 _bcm_td_cpq_en_field[qindex])) { 6601 *index = soc_mem_field32_get(unit, MMU_QCN_ENABLEm, &entry, 6602 _bcm_td_cpq_index_field[qindex]); 6603 } else { 6604 *index = -1; 6605 } 6606 6607 return BCM_E_NONE; 6608 } 6609 6610 /* 6611 * Function: 6612 * bcm_td_cosq_congestion_quantize_set 6613 * Purpose: 6614 * Set quantized congestion feedback algorithm parameters 6615 * Parameters: 6616 * unit - (IN) unit number 6617 * port - (IN) port number or GPORT identifier 6618 * cosq - (IN) COS queue number 6619 * weight_code - (IN) weight encoding (use -1 for unchange) 6620 * set_point - (IN) queue size set point (use -1 for unchange) 6621 * Returns: 6622 * BCM_E_XXX 6623 */ 6624 int 6625 bcm_td_cosq_congestion_quantize_set(int unit, bcm_port_t port, 6626 bcm_cos_queue_t cosq, int weight_code, 6627 int set_point) 6628 { 6629 soc_info_t *si; 6630 bcm_port_t local_port; 6631 int phy_port, mmu_port; 6632 uint32 rval; 6633 uint64 rval64, *rval64s[1]; 6634 mmu_qcn_cpqcfg_entry_t entry; 6635 int cpq_index, active_offset; 6636 uint32 profile_index, old_profile_index; 6637 6638 si = &SOC_INFO(unit); 6639 6640 BCM_IF_ERROR_RETURN 6641 (_bcm_td_cosq_index_resolve(unit, port, cosq, 6642 _BCM_TD_COSQ_INDEX_STYLE_UCAST_QUEUE, 6643 &local_port, NULL, NULL)); 6644 6645 BCM_IF_ERROR_RETURN 6646 (bcm_td_cosq_congestion_queue_get(unit, port, cosq, &cpq_index)); 6647 if (cpq_index == -1) { 6648 /* The cosq specified is not enabled as congestion managed queue */ 6649 return BCM_E_PARAM; 6650 } 6651 6652 phy_port = si->port_l2p_mapping[local_port]; 6653 mmu_port = si->port_p2m_mapping[phy_port]; 6654 6655 BCM_IF_ERROR_RETURN 6656 (soc_mem_read(unit, MMU_QCN_CPQCFGm, MEM_BLOCK_ANY, mmu_port, &entry)); 6657 old_profile_index = 6658 soc_mem_field32_get(unit, MMU_QCN_CPQCFGm, &entry, 6659 _bcm_td_eqtb_index_field[cpq_index]); 6660 6661 BCM_IF_ERROR_RETURN(READ_MMU_QCN_CPQ_SEQr(unit, old_profile_index, &rval)); 6662 if (weight_code == -1) { 6663 weight_code = soc_reg_field_get(unit, MMU_QCN_CPQ_SEQr, rval, CPWf); 6664 } else { 6665 if (weight_code < 0 || weight_code > 7) { 6666 return BCM_E_PARAM; 6667 } 6668 soc_reg_field_set(unit, MMU_QCN_CPQ_SEQr, &rval, CPWf, weight_code); 6669 } 6670 if (set_point == -1) { 6671 set_point = soc_reg_field_get(unit, MMU_QCN_CPQ_SEQr, rval, CPQEQf); 6672 } else { 6673 if (set_point < 0 || set_point > 0xffff) { 6674 return BCM_E_PARAM; 6675 } 6676 soc_reg_field_set(unit, MMU_QCN_CPQ_SEQr, &rval, CPQEQf, set_point); 6677 } 6678 COMPILER_64_SET(rval64, 0, rval); 6679 rval64s[0] = &rval64; 6680 /* Add new feedback parameter profile */ 6681 BCM_IF_ERROR_RETURN 6682 (soc_profile_reg_add(unit, _bcm_td_feedback_profile[unit], rval64s, 6683 1, (uint32 *)&profile_index)); 6684 /* Delete original feedback parameter profile */ 6685 BCM_IF_ERROR_RETURN 6686 (soc_profile_reg_delete(unit, _bcm_td_feedback_profile[unit], 6687 old_profile_index)); 6688 6689 /* Update quantized feedback calculation lookup table */ 6690 BCM_IF_ERROR_RETURN 6691 (_bcm_td_cosq_quantize_table_set(unit, profile_index, weight_code, 6692 set_point, &active_offset)); 6693 6694 soc_mem_field32_set(unit, MMU_QCN_CPQCFGm, &entry, 6695 _bcm_td_act_offset_field[cpq_index], active_offset); 6696 soc_mem_field32_set(unit, MMU_QCN_CPQCFGm, &entry, 6697 _bcm_td_eqtb_index_field[cpq_index], profile_index); 6698 BCM_IF_ERROR_RETURN(soc_mem_write(unit, MMU_QCN_CPQCFGm, MEM_BLOCK_ANY, 6699 mmu_port, &entry)); 6700 6701 return BCM_E_NONE; 6702 } 6703 6704 /* 6705 * Function: 6706 * bcm_td_cosq_congestion_quantize_get 6707 * Purpose: 6708 * Get quantized congestion feedback algorithm parameters 6709 * Parameters: 6710 * unit - (IN) unit number 6711 * port - (IN) port number or GPORT identifier 6712 * cosq - (IN) COS queue number 6713 * weight_code - (OUT) weight encoding 6714 * set_point - (OUT) queue size set point 6715 * Returns: 6716 * BCM_E_XXX 6717 */ 6718 int 6719 bcm_td_cosq_congestion_quantize_get(int unit, bcm_port_t port, 6720 bcm_cos_queue_t cosq, int *weight_code, 6721 int *set_point) 6722 { 6723 soc_info_t *si; 6724 bcm_port_t local_port; 6725 int phy_port, mmu_port; 6726 int cpq_index, profile_index; 6727 uint32 rval; 6728 mmu_qcn_cpqcfg_entry_t entry; 6729 6730 si = &SOC_INFO(unit); 6731 6732 BCM_IF_ERROR_RETURN 6733 (_bcm_td_cosq_index_resolve(unit, port, cosq, 6734 _BCM_TD_COSQ_INDEX_STYLE_UCAST_QUEUE, 6735 &local_port, NULL, NULL)); 6736 6737 BCM_IF_ERROR_RETURN 6738 (bcm_td_cosq_congestion_queue_get(unit, port, cosq, &cpq_index)); 6739 if (cpq_index == -1) { 6740 /* The cosq specified is not enabled as congestion managed queue */ 6741 return BCM_E_PARAM; 6742 } 6743 6744 phy_port = si->port_l2p_mapping[local_port]; 6745 mmu_port = si->port_p2m_mapping[phy_port]; 6746 6747 BCM_IF_ERROR_RETURN 6748 (soc_mem_read(unit, MMU_QCN_CPQCFGm, MEM_BLOCK_ANY, mmu_port, &entry)); 6749 profile_index = soc_mem_field32_get(unit, MMU_QCN_CPQCFGm, &entry, 6750 _bcm_td_eqtb_index_field[cpq_index]); 6751 6752 BCM_IF_ERROR_RETURN(READ_MMU_QCN_CPQ_SEQr(unit, profile_index, &rval)); 6753 if (weight_code != NULL) { 6754 *weight_code = soc_reg_field_get(unit, MMU_QCN_CPQ_SEQr, rval, CPWf); 6755 } 6756 if (set_point != NULL) { 6757 *set_point = soc_reg_field_get(unit, MMU_QCN_CPQ_SEQr, rval, CPQEQf); 6758 } 6759 6760 return BCM_E_NONE; 6761 } 6762 6763 int 6764 bcm_td_cosq_congestion_sample_int_set(int unit, bcm_port_t port, 6765 bcm_cos_queue_t cosq, int min, int max) 6766 { 6767 soc_info_t *si; 6768 bcm_port_t local_port; 6769 int phy_port, mmu_port; 6770 mmu_qcn_cpqcfg_entry_t cpqcfg_entry; 6771 mmu_qcn_sitb_entry_t sitb_entry; 6772 int cpq_index; 6773 uint32 profile_index, old_profile_index; 6774 6775 si = &SOC_INFO(unit); 6776 6777 BCM_IF_ERROR_RETURN 6778 (_bcm_td_cosq_index_resolve(unit, port, cosq, 6779 _BCM_TD_COSQ_INDEX_STYLE_UCAST_QUEUE, 6780 &local_port, NULL, NULL)); 6781 6782 BCM_IF_ERROR_RETURN 6783 (bcm_td_cosq_congestion_queue_get(unit, port, cosq, &cpq_index)); 6784 if (cpq_index == -1) { 6785 /* The cosq specified is not enabled as congestion managed queue */ 6786 return BCM_E_PARAM; 6787 } 6788 6789 phy_port = si->port_l2p_mapping[local_port]; 6790 mmu_port = si->port_p2m_mapping[phy_port]; 6791 6792 BCM_IF_ERROR_RETURN(soc_mem_read(unit, MMU_QCN_CPQCFGm, MEM_BLOCK_ANY, 6793 mmu_port, &cpqcfg_entry)); 6794 old_profile_index = 6795 soc_mem_field32_get(unit, MMU_QCN_CPQCFGm, &cpqcfg_entry, 6796 _bcm_td_sitb_sel_field[cpq_index]); 6797 6798 if (max == -1) { 6799 BCM_IF_ERROR_RETURN(soc_mem_read(unit, MMU_QCN_SITBm, MEM_BLOCK_ANY, 6800 old_profile_index * 64, &sitb_entry)); 6801 max = soc_mem_field32_get(unit, MMU_QCN_SITBm, &sitb_entry, CPQ_SIf); 6802 } else { 6803 if (max < 1 || max > 255) { 6804 return BCM_E_PARAM; 6805 } 6806 } 6807 if (min == -1) { 6808 BCM_IF_ERROR_RETURN(soc_mem_read(unit, MMU_QCN_SITBm, MEM_BLOCK_ANY, 6809 old_profile_index * 64 + 56, 6810 &sitb_entry)); 6811 min = soc_mem_field32_get(unit, MMU_QCN_SITBm, &sitb_entry, CPQ_SIf); 6812 } else { 6813 if (min < 1 || min > 255) { 6814 return BCM_E_PARAM; 6815 } 6816 } 6817 6818 /* Add new sample interval profile */ 6819 BCM_IF_ERROR_RETURN 6820 (_bcm_td_cosq_sample_int_table_set(unit, min, max, &profile_index)); 6821 6822 /* Delete original sample interval profile */ 6823 BCM_IF_ERROR_RETURN 6824 (soc_profile_mem_delete(unit, _bcm_td_sample_int_profile[unit], 6825 old_profile_index * 64)); 6826 6827 soc_mem_field32_set(unit, MMU_QCN_CPQCFGm, &cpqcfg_entry, 6828 _bcm_td_sitb_sel_field[cpq_index], profile_index / 64); 6829 BCM_IF_ERROR_RETURN(soc_mem_write(unit, MMU_QCN_CPQCFGm, MEM_BLOCK_ANY, 6830 mmu_port, &cpqcfg_entry)); 6831 6832 return BCM_E_NONE; 6833 } 6834 6835 int 6836 bcm_td_cosq_congestion_sample_int_get(int unit, bcm_port_t port, 6837 bcm_cos_queue_t cosq, int *min, int *max) 6838 { 6839 soc_info_t *si; 6840 bcm_port_t local_port; 6841 int phy_port, mmu_port; 6842 mmu_qcn_cpqcfg_entry_t cpqcfg_entry; 6843 mmu_qcn_sitb_entry_t sitb_entry; 6844 int cpq_index, profile_index; 6845 6846 si = &SOC_INFO(unit); 6847 6848 BCM_IF_ERROR_RETURN 6849 (_bcm_td_cosq_index_resolve(unit, port, cosq, 6850 _BCM_TD_COSQ_INDEX_STYLE_UCAST_QUEUE, 6851 &local_port, NULL, NULL)); 6852 6853 BCM_IF_ERROR_RETURN 6854 (bcm_td_cosq_congestion_queue_get(unit, port, cosq, &cpq_index)); 6855 if (cpq_index == -1) { 6856 /* The cosq specified is not enabled as congestion managed queue */ 6857 return BCM_E_PARAM; 6858 } 6859 6860 phy_port = si->port_l2p_mapping[local_port]; 6861 mmu_port = si->port_p2m_mapping[phy_port]; 6862 6863 BCM_IF_ERROR_RETURN(soc_mem_read(unit, MMU_QCN_CPQCFGm, MEM_BLOCK_ANY, 6864 mmu_port, &cpqcfg_entry)); 6865 profile_index = soc_mem_field32_get(unit, MMU_QCN_CPQCFGm, &cpqcfg_entry, 6866 _bcm_td_sitb_sel_field[cpq_index]); 6867 6868 if (max != NULL) { 6869 BCM_IF_ERROR_RETURN(soc_mem_read(unit, MMU_QCN_SITBm, MEM_BLOCK_ANY, 6870 profile_index * 64, &sitb_entry)); 6871 *max = soc_mem_field32_get(unit, MMU_QCN_SITBm, &sitb_entry, CPQ_SIf); 6872 } 6873 if (min != NULL) { 6874 BCM_IF_ERROR_RETURN(soc_mem_read(unit, MMU_QCN_SITBm, MEM_BLOCK_ANY, 6875 profile_index * 64 + 56, 6876 &sitb_entry)); 6877 *min = soc_mem_field32_get(unit, MMU_QCN_SITBm, &sitb_entry, CPQ_SIf); 6878 } 6879 6880 return BCM_E_NONE; 6881 } 6882 6883 int 6884 bcm_td_cosq_drop_status_enable_set(int unit, bcm_port_t port, int enable) 6885 { 6886 soc_info_t *si; 6887 soc_mem_t mem; 6888 int phy_port, mmu_port, base, count, idx; 6889 uint32 rval; 6890 6891 si = &SOC_INFO(unit); 6892 6893 /* Multicast queue */ 6894 count = IS_LB_PORT(unit, port) ? 5 : si->port_num_cosq[port]; 6895 for (idx = 0; idx < count; idx++) { 6896 SOC_IF_ERROR_RETURN 6897 (READ_OP_QUEUE_CONFIG1_CELLr(unit, port, idx, &rval)); 6898 soc_reg_field_set(unit,OP_QUEUE_CONFIG1_CELLr, &rval, 6899 Q_E2E_DS_EN_CELLf, enable ? 1 : 0); 6900 SOC_IF_ERROR_RETURN 6901 (WRITE_OP_QUEUE_CONFIG1_CELLr(unit, port, idx, rval)); 6902 } 6903 6904 phy_port = si->port_l2p_mapping[port]; 6905 mmu_port = si->port_p2m_mapping[phy_port]; 6906 if (si->port_num_ext_cosq[port] == 0) { /* regular port */ 6907 /* Regular unicast queue */ 6908 if (SOC_PBMP_MEMBER(si->xpipe_pbm, port)) { /* X pipe */ 6909 mem = MMU_THDO_CONFIG_0m; 6910 /* Index starts from mmu port 5, 10 entries per port */ 6911 base = (mmu_port - 5) * 10; 6912 } else { /* Y pipe */ 6913 mem = MMU_THDO_CONFIG_1m; 6914 /* Index starts from mmu port 38, 10 entries per port */ 6915 base = (mmu_port - 38) * 10; 6916 } 6917 for (idx = 0; idx < si->port_num_uc_cosq[port]; idx++) { 6918 SOC_IF_ERROR_RETURN 6919 (soc_mem_field32_modify(unit, mem, base + idx, 6920 Q_E2E_DS_EN_CELLf, 1)); 6921 } 6922 } else { /* extended queue port */ 6923 /* 6924 * Depends on OP_VOQ_PORT_CONFIG mode setting for the extended 6925 * queue port: 6926 * - cos mode 6927 * use MMU_THDO_CONFIG_SP_x table, 10 entries per port 6928 * - queue mode 6929 * use MMU_THDO_CONFIG_EX_x table, 74 entries per port 6930 * extended unicast queue: index 0-63 6931 * regular unicast queue: index 64-73 6932 */ 6933 /* Regular unicast queue in queue mode and extended unicast queue */ 6934 if (SOC_PBMP_MEMBER(si->xpipe_pbm, port)) { /* X pipe */ 6935 mem = MMU_THDO_CONFIG_EX_0m; 6936 /* Index starts from mmu port 1, 74 entries per port */ 6937 base = (mmu_port - 1) * 74; 6938 } else { /* Y pipe */ 6939 mem = MMU_THDO_CONFIG_EX_1m; 6940 /* Index starts from mmu port 34, 74 entries per port */ 6941 base = (mmu_port - 34) * 74; 6942 } 6943 count = si->port_num_uc_cosq[port] + si->port_num_ext_cosq[port]; 6944 for (idx = 0; idx < count; idx++) { 6945 SOC_IF_ERROR_RETURN 6946 (soc_mem_field32_modify(unit, mem, base + idx, 6947 Q_E2E_DS_EN_CELLf, enable ? 1 : 0)); 6948 } 6949 6950 /* Regular unicast queue in cos mode */ 6951 if (SOC_PBMP_MEMBER(si->xpipe_pbm, port)) { /* X pipe */ 6952 mem = MMU_THDO_CONFIG_SP_0m; 6953 /* Index starts from mmu port 1, 10 entries per port */ 6954 base = (mmu_port - 1) * 10; 6955 } else { /* Y pipe */ 6956 mem = MMU_THDO_CONFIG_SP_1m; 6957 /* Index starts from mmu port 34, 10 entries per port */ 6958 base = (mmu_port - 34) * 10; 6959 } 6960 for (idx = 0; idx < si->port_num_uc_cosq[port]; idx++) { 6961 SOC_IF_ERROR_RETURN 6962 (soc_mem_field32_modify(unit, mem, base + idx, 6963 Q_E2E_DS_EN_CELLf, enable ? 1 : 0)); 6964 } 6965 } 6966 6967 /* Regular unicast queue */ 6968 SOC_IF_ERROR_RETURN(READ_OP_UC_PORT_CONFIG1_CELLr(unit, port, &rval)); 6969 soc_reg_field_set(unit,OP_UC_PORT_CONFIG1_CELLr, &rval, 6970 Q_E2E_DS_ENf, enable ? 0xff : 0); 6971 SOC_IF_ERROR_RETURN(WRITE_OP_UC_PORT_CONFIG1_CELLr(unit, port, rval)); 6972 6973 SOC_IF_ERROR_RETURN(READ_OP_THR_CONFIGr(unit, &rval)); 6974 soc_reg_field_set(unit, OP_THR_CONFIGr, &rval, EARLY_E2E_SELECTf, 6975 enable ? 1 : 0); 6976 SOC_IF_ERROR_RETURN(WRITE_OP_THR_CONFIGr(unit, rval)); 6977 6978 return BCM_E_NONE; 6979 } 6980 6981 STATIC int 6982 _bcm_td_cosq_egr_pool_set(int unit, bcm_gport_t gport, bcm_cos_queue_t cosq, 6983 bcm_cosq_control_t type, int arg) 6984 { 6985 bcm_port_t local_port; 6986 int id, startq, pool; 6987 soc_reg_t reg; 6988 soc_field_t field; 6989 uint32 rval; 6990 int num_cells, default_mtu_cells; 6991 soc_info_t *si; 6992 6993 num_cells = 0; 6994 default_mtu_cells = _BCM_TD_BYTES_TO_CELLS(_BCM_TD_DEFAULT_MTU_BYTES + 6995 _BCM_TD_PACKET_HEADER_BYTES); 6996 si = &SOC_INFO(unit); 6997 6998 if (type == bcmCosqControlUCEgressPool) { 6999 BCM_IF_ERROR_RETURN 7000 (_bcm_td_cosq_index_resolve(unit, gport, cosq, 7001 _BCM_TD_COSQ_INDEX_STYLE_UC_EGR_POOL, 7002 &local_port, &startq, NULL)); 7003 } else { 7004 BCM_IF_ERROR_RETURN 7005 (_bcm_td_cosq_index_resolve(unit, gport, cosq, 7006 _BCM_TD_COSQ_INDEX_STYLE_EGR_POOL, 7007 &local_port, &startq, NULL)); 7008 } 7009 if (type == bcmCosqControlEgressPoolLimitEnable) { 7010 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 7011 reg = OP_UC_PORT_CONFIG1_CELLr; 7012 } else { 7013 reg = OP_PORT_CONFIG1_CELLr; 7014 } 7015 BCM_IF_ERROR_RETURN(soc_reg32_get(unit, reg, local_port, 0, &rval)); 7016 soc_reg_field_set(unit, reg, &rval, PORT_LIMIT_ENABLE_CELLf, 7017 arg ? 1 : 0); 7018 BCM_IF_ERROR_RETURN(soc_reg32_set(unit, reg, local_port, 0, rval)); 7019 return BCM_E_NONE; 7020 } else if (type == bcmCosqControlEgressPool) { 7021 if (arg < 0 || arg > 3) { 7022 return BCM_E_PARAM; 7023 } 7024 } else if (type == bcmCosqControlUCEgressPool || type == bcmCosqControlMCEgressPool) { 7025 if (arg < 0 || arg > 3) { 7026 return BCM_E_PARAM; 7027 } 7028 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport) || BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 7029 return BCM_E_PARAM; 7030 } 7031 } else if (type == bcmCosqControlEgressPoolLimitBytes || 7032 type == bcmCosqControlEgressPoolYellowLimitBytes || 7033 type == bcmCosqControlEgressPoolRedLimitBytes) { 7034 if (arg < 0) { 7035 return BCM_E_PARAM; 7036 } 7037 num_cells = arg / _BCM_TD_BYTES_PER_CELL; 7038 if (num_cells > _BCM_TD_TOTAL_CELLS) { 7039 return BCM_E_PARAM; 7040 } 7041 } 7042 7043 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 7044 BCM_IF_ERROR_RETURN 7045 (_bcm_td_cosq_node_get(unit, gport, NULL, NULL, &id, NULL)); 7046 if (id < _BCM_TD_NUM_UCAST_QUEUE_GROUP) { 7047 reg = OP_UC_PORT_CONFIG1_CELLr; 7048 field = _bcm_td_uc_spid_fields[startq]; 7049 /* regular unicast queue */ 7050 } else { 7051 /* extended unicast queue */ 7052 reg = _bcm_td_ext_uc_spid_regs[startq / 16]; 7053 field = _bcm_td_ext_uc_spid_fields[startq]; 7054 } 7055 startq = 0; 7056 } else if (type == bcmCosqControlUCEgressPool) { 7057 if (si->port_num_ext_cosq[local_port] == 0) { 7058 /* regular unicast queue */ 7059 reg = OP_UC_PORT_CONFIG1_CELLr; 7060 field = _bcm_td_uc_spid_fields[startq]; 7061 } else { 7062 /* extended unicast queue */ 7063 reg = _bcm_td_ext_uc_spid_regs[(startq + 64) / 16]; 7064 field = _bcm_td_ext_uc_spid_fields[startq + 64]; 7065 } 7066 } else { /* multicast queue group or local port */ 7067 reg = OP_QUEUE_CONFIG1_CELLr; 7068 field = Q_SPIDf; 7069 } 7070 7071 BCM_IF_ERROR_RETURN(soc_reg32_get(unit, reg, local_port, startq, &rval)); 7072 if (type == bcmCosqControlEgressPool || type == bcmCosqControlUCEgressPool || 7073 type == bcmCosqControlMCEgressPool) { 7074 soc_reg_field_set(unit, reg, &rval, field, arg); 7075 BCM_IF_ERROR_RETURN 7076 (soc_reg32_set(unit, reg, local_port, startq, rval)); 7077 return BCM_E_NONE; 7078 } 7079 7080 pool = soc_reg_field_get(unit, reg, rval, field); 7081 switch (type) { 7082 case bcmCosqControlEgressPoolLimitBytes: 7083 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 7084 reg = OP_UC_PORT_CONFIG_CELLr; 7085 } else { 7086 reg = OP_PORT_CONFIG_CELLr; 7087 } 7088 BCM_IF_ERROR_RETURN(soc_reg32_get(unit, reg, local_port, pool, &rval)); 7089 soc_reg_field_set(unit, reg, &rval, OP_SHARED_LIMIT_CELLf, num_cells); 7090 num_cells = num_cells > default_mtu_cells ? 7091 num_cells - default_mtu_cells : 0; 7092 soc_reg_field_set(unit, reg, &rval, OP_SHARED_RESET_VALUE_CELLf, 7093 num_cells); 7094 BCM_IF_ERROR_RETURN(soc_reg32_set(unit, reg, local_port, pool, rval)); 7095 break; 7096 case bcmCosqControlEgressPoolYellowLimitBytes: 7097 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 7098 reg = OP_UC_PORT_LIMIT_COLOR_CELLr; 7099 } else { 7100 return BCM_E_PARAM; 7101 } 7102 BCM_IF_ERROR_RETURN(soc_reg32_get(unit, reg, local_port, pool, &rval)); 7103 /* granularity for color limit is 8 cells */ 7104 soc_reg_field_set(unit, reg, &rval, YELf, num_cells / 8); 7105 BCM_IF_ERROR_RETURN(soc_reg32_set(unit, reg, local_port, pool, rval)); 7106 break; 7107 case bcmCosqControlEgressPoolRedLimitBytes: 7108 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 7109 reg = OP_UC_PORT_LIMIT_COLOR_CELLr; 7110 } else { 7111 reg = OP_PORT_LIMIT_COLOR_CELLr; 7112 } 7113 BCM_IF_ERROR_RETURN(soc_reg32_get(unit, reg, local_port, pool, &rval)); 7114 /* granularity for color limit is 8 cells */ 7115 soc_reg_field_set(unit, reg, &rval, REDf, num_cells / 8); 7116 BCM_IF_ERROR_RETURN(soc_reg32_set(unit, reg, local_port, pool, rval)); 7117 break; 7118 default: 7119 return BCM_E_UNAVAIL; 7120 } 7121 7122 return BCM_E_NONE; 7123 } 7124 7125 STATIC int 7126 _bcm_td_cosq_egr_pool_get(int unit, bcm_gport_t gport, bcm_cos_queue_t cosq, 7127 bcm_cosq_control_t type, int *arg) 7128 { 7129 bcm_port_t local_port; 7130 int id, startq, pool; 7131 soc_reg_t reg; 7132 soc_field_t field; 7133 uint32 rval; 7134 soc_info_t *si; 7135 si = &SOC_INFO(unit); 7136 7137 if (type == bcmCosqControlUCEgressPool) { 7138 BCM_IF_ERROR_RETURN 7139 (_bcm_td_cosq_index_resolve(unit, gport, cosq, 7140 _BCM_TD_COSQ_INDEX_STYLE_UC_EGR_POOL, 7141 &local_port, &startq, NULL)); 7142 } else { 7143 BCM_IF_ERROR_RETURN 7144 (_bcm_td_cosq_index_resolve(unit, gport, cosq, 7145 _BCM_TD_COSQ_INDEX_STYLE_EGR_POOL, 7146 &local_port, &startq, NULL)); 7147 } 7148 if (type == bcmCosqControlEgressPoolLimitEnable) { 7149 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 7150 reg = OP_UC_PORT_CONFIG1_CELLr; 7151 } else { 7152 reg = OP_PORT_CONFIG1_CELLr; 7153 } 7154 BCM_IF_ERROR_RETURN(soc_reg32_get(unit, reg, local_port, 0, &rval)); 7155 *arg = soc_reg_field_get(unit, reg, rval, PORT_LIMIT_ENABLE_CELLf); 7156 return BCM_E_NONE; 7157 } 7158 7159 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 7160 BCM_IF_ERROR_RETURN 7161 (_bcm_td_cosq_node_get(unit, gport, NULL, NULL, &id, NULL)); 7162 if (id < _BCM_TD_NUM_UCAST_QUEUE_GROUP) { 7163 reg = OP_UC_PORT_CONFIG1_CELLr; 7164 field = _bcm_td_uc_spid_fields[startq]; 7165 /* regular unicast queue */ 7166 } else { 7167 /* extended unicast queue */ 7168 reg = _bcm_td_ext_uc_spid_regs[startq / 16]; 7169 field = _bcm_td_ext_uc_spid_fields[startq]; 7170 } 7171 startq = 0; 7172 } else if (type == bcmCosqControlUCEgressPool) { 7173 if (si->port_num_ext_cosq[local_port] == 0) { 7174 /* regular unicast queue */ 7175 reg = OP_UC_PORT_CONFIG1_CELLr; 7176 field = _bcm_td_uc_spid_fields[startq]; 7177 } else { 7178 /* extended unicast queue */ 7179 reg = _bcm_td_ext_uc_spid_regs[(startq + 64)/16]; 7180 field = _bcm_td_ext_uc_spid_fields[startq + 64]; 7181 } 7182 } else { /* multicast queue group or local port */ 7183 reg = OP_QUEUE_CONFIG1_CELLr; 7184 field = Q_SPIDf; 7185 } 7186 7187 BCM_IF_ERROR_RETURN(soc_reg32_get(unit, reg, local_port, startq, &rval)); 7188 pool = soc_reg_field_get(unit, reg, rval, field); 7189 if (type == bcmCosqControlEgressPool || type == bcmCosqControlUCEgressPool || 7190 type == bcmCosqControlMCEgressPool) { 7191 *arg = pool; 7192 return BCM_E_NONE; 7193 } 7194 7195 switch (type) { 7196 case bcmCosqControlEgressPoolLimitBytes: 7197 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 7198 reg = OP_UC_PORT_CONFIG_CELLr; 7199 } else { 7200 reg = OP_PORT_CONFIG_CELLr; 7201 } 7202 BCM_IF_ERROR_RETURN(soc_reg32_get(unit, reg, local_port, pool, &rval)); 7203 *arg = soc_reg_field_get(unit, reg, rval, OP_SHARED_LIMIT_CELLf) * 7204 _BCM_TD_BYTES_PER_CELL; 7205 break; 7206 case bcmCosqControlEgressPoolYellowLimitBytes: 7207 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 7208 reg = OP_UC_PORT_LIMIT_COLOR_CELLr; 7209 } else { 7210 return BCM_E_PARAM; 7211 } 7212 BCM_IF_ERROR_RETURN(soc_reg32_get(unit, reg, local_port, pool, &rval)); 7213 /* granularity for color limit is 8 cells */ 7214 *arg = soc_reg_field_get(unit, reg, rval, YELf) * 8 * 7215 _BCM_TD_BYTES_PER_CELL; 7216 break; 7217 case bcmCosqControlEgressPoolRedLimitBytes: 7218 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 7219 reg = OP_UC_PORT_LIMIT_COLOR_CELLr; 7220 } else { 7221 reg = OP_PORT_LIMIT_COLOR_CELLr; 7222 } 7223 BCM_IF_ERROR_RETURN(soc_reg32_get(unit, reg, local_port, pool, &rval)); 7224 /* granularity for color limit is 8 cells */ 7225 *arg = soc_reg_field_get(unit, reg, rval, REDf) * 8 * 7226 _BCM_TD_BYTES_PER_CELL; 7227 break; 7228 default: 7229 return BCM_E_UNAVAIL; 7230 } 7231 7232 return BCM_E_NONE; 7233 } 7234 7235 STATIC int 7236 _bcm_td_cosq_alpha_set(int unit, 7237 bcm_gport_t gport, bcm_cos_queue_t cosq, 7238 bcm_cosq_control_drop_limit_alpha_value_t arg) 7239 { 7240 bcm_port_t local_port; 7241 int id,startq; 7242 uint32 entry[SOC_MAX_MEM_WORDS]; 7243 soc_mem_t mem = INVALIDm; 7244 soc_info_t *si; 7245 int alpha; 7246 uint32 rval; 7247 int dynamic_thresh_mode; 7248 int port_pg; 7249 soc_reg_t reg = INVALIDr; 7250 static const soc_reg_t prigroup_reg[] = { 7251 PORT_PRI_GRP0r, PORT_PRI_GRP1r 7252 }; 7253 static const soc_field_t prigroup_field[] = { 7254 PRI0_GRPf, PRI1_GRPf, PRI2_GRPf, PRI3_GRPf, 7255 PRI4_GRPf, PRI5_GRPf, PRI6_GRPf, PRI7_GRPf, 7256 PRI8_GRPf, PRI9_GRPf, PRI10_GRPf, PRI11_GRPf, 7257 PRI12_GRPf, PRI13_GRPf, PRI14_GRPf, PRI15_GRPf 7258 }; 7259 7260 switch(arg) { 7261 case bcmCosqControlDropLimitAlpha_1_64: 7262 alpha = SOC_TD_COSQ_DROP_LIMIT_ALPHA_1_64; 7263 break; 7264 case bcmCosqControlDropLimitAlpha_1_32: 7265 alpha = SOC_TD_COSQ_DROP_LIMIT_ALPHA_1_32; 7266 break; 7267 case bcmCosqControlDropLimitAlpha_1_16: 7268 alpha = SOC_TD_COSQ_DROP_LIMIT_ALPHA_1_16; 7269 break; 7270 case bcmCosqControlDropLimitAlpha_1_8: 7271 alpha = SOC_TD_COSQ_DROP_LIMIT_ALPHA_1_8; 7272 break; 7273 case bcmCosqControlDropLimitAlpha_1_4: 7274 alpha = SOC_TD_COSQ_DROP_LIMIT_ALPHA_1_4; 7275 break; 7276 case bcmCosqControlDropLimitAlpha_1_2: 7277 alpha = SOC_TD_COSQ_DROP_LIMIT_ALPHA_1_2; 7278 break; 7279 case bcmCosqControlDropLimitAlpha_1: 7280 alpha = SOC_TD_COSQ_DROP_LIMIT_ALPHA_1; 7281 break; 7282 case bcmCosqControlDropLimitAlpha_2: 7283 alpha = SOC_TD_COSQ_DROP_LIMIT_ALPHA_2; 7284 break; 7285 case bcmCosqControlDropLimitAlpha_4: 7286 alpha = SOC_TD_COSQ_DROP_LIMIT_ALPHA_4; 7287 break; 7288 case bcmCosqControlDropLimitAlpha_8: 7289 alpha = SOC_TD_COSQ_DROP_LIMIT_ALPHA_8; 7290 break; 7291 default: 7292 return BCM_E_PARAM; 7293 } 7294 7295 si = &SOC_INFO(unit); 7296 7297 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 7298 BCM_IF_ERROR_RETURN 7299 (_bcm_td_cosq_dynamic_thresh_enable_get(unit, gport, cosq, 7300 bcmCosqControlEgressUCSharedDynamicEnable, 7301 &dynamic_thresh_mode)); 7302 if (!dynamic_thresh_mode){ 7303 return BCM_E_CONFIG; 7304 } 7305 7306 BCM_IF_ERROR_RETURN 7307 (_bcm_td_cosq_index_resolve(unit, gport, cosq, 7308 _BCM_TD_COSQ_INDEX_STYLE_UCAST_QUEUE, 7309 &local_port, &startq, NULL)); 7310 BCM_IF_ERROR_RETURN 7311 (_bcm_td_cosq_node_get(unit, gport, NULL, NULL, &id, NULL)); 7312 if (id < _BCM_TD_NUM_UCAST_QUEUE_GROUP) { 7313 /* regular unicast queue */ 7314 if (SOC_PBMP_MEMBER(si->xpipe_pbm, local_port)) { /* X pipe */ 7315 mem = MMU_THDO_CONFIG_0m; 7316 } else { /* Y pipe */ 7317 mem = MMU_THDO_CONFIG_1m; 7318 } 7319 } else { 7320 /* extended unicast queue */ 7321 if (SOC_PBMP_MEMBER(si->xpipe_pbm, local_port)) { /* X pipe */ 7322 mem = MMU_THDO_CONFIG_EX_0m; 7323 } else { /* Y pipe */ 7324 mem = MMU_THDO_CONFIG_EX_1m; 7325 } 7326 } 7327 BCM_IF_ERROR_RETURN 7328 (soc_mem_read(unit, mem, MEM_BLOCK_ALL, startq, entry)); 7329 soc_mem_field32_set(unit, mem, entry, 7330 Q_SHARED_ALPHA_CELLf, alpha); 7331 SOC_IF_ERROR_RETURN 7332 (soc_mem_write(unit, mem, MEM_BLOCK_ALL, startq, entry)); 7333 7334 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 7335 BCM_IF_ERROR_RETURN 7336 (_bcm_td_cosq_dynamic_thresh_enable_get(unit, gport, cosq, 7337 bcmCosqControlEgressMCSharedDynamicEnable, 7338 &dynamic_thresh_mode)); 7339 if (!dynamic_thresh_mode){ 7340 return BCM_E_CONFIG; 7341 } 7342 7343 BCM_IF_ERROR_RETURN 7344 (_bcm_td_cosq_index_resolve(unit, gport, cosq, 7345 _BCM_TD_COSQ_INDEX_STYLE_MCAST_QUEUE, 7346 &local_port, &startq, NULL)); 7347 BCM_IF_ERROR_RETURN 7348 (READ_OP_QUEUE_CONFIG_CELLr(unit, local_port, cosq, &rval)); 7349 soc_reg_field_set(unit, OP_QUEUE_CONFIG_CELLr, &rval, 7350 Q_SHARED_ALPHA_CELLf, alpha); 7351 BCM_IF_ERROR_RETURN 7352 (WRITE_OP_QUEUE_CONFIG_CELLr(unit, local_port, cosq, rval)); 7353 7354 } else { 7355 BCM_IF_ERROR_RETURN 7356 (_bcm_td_cosq_dynamic_thresh_enable_get(unit, gport, cosq, 7357 bcmCosqControlIngressPortPGSharedDynamicEnable, 7358 &dynamic_thresh_mode)); 7359 if (!dynamic_thresh_mode){ 7360 return BCM_E_CONFIG; 7361 } 7362 7363 BCM_IF_ERROR_RETURN 7364 (_bcm_td_cosq_localport_resolve(unit, gport, &local_port)); 7365 if (local_port < 0) { 7366 return BCM_E_PORT; 7367 } 7368 7369 /* get PG for port using Port+Cos */ 7370 if (cosq < 8) { 7371 reg = prigroup_reg[0]; 7372 } else { 7373 reg = prigroup_reg[1]; 7374 } 7375 7376 SOC_IF_ERROR_RETURN 7377 (soc_reg32_get(unit, reg, local_port, 0, &rval)); 7378 port_pg = soc_reg_field_get(unit, reg, rval, prigroup_field[cosq]); 7379 7380 SOC_IF_ERROR_RETURN 7381 (READ_PG_SHARED_LIMIT_CELLr(unit, local_port, port_pg, &rval)); 7382 soc_reg_field_set(unit, PG_SHARED_LIMIT_CELLr, &rval, 7383 PG_SHARED_LIMITf, alpha); 7384 SOC_IF_ERROR_RETURN 7385 (WRITE_PG_SHARED_LIMIT_CELLr(unit, local_port, port_pg, rval)); 7386 } 7387 7388 return BCM_E_NONE; 7389 } 7390 7391 STATIC int 7392 _bcm_td_cosq_alpha_get(int unit, 7393 bcm_gport_t gport, bcm_cos_queue_t cosq, 7394 bcm_cosq_control_drop_limit_alpha_value_t *arg) 7395 { 7396 bcm_port_t local_port; 7397 int id,startq; 7398 uint32 entry[SOC_MAX_MEM_WORDS]; 7399 soc_mem_t mem = INVALIDm; 7400 soc_info_t *si; 7401 int alpha; 7402 uint32 rval; 7403 int dynamic_thresh_mode; 7404 int port_pg; 7405 soc_reg_t reg = INVALIDr; 7406 static const soc_reg_t prigroup_reg[] = { 7407 PORT_PRI_GRP0r, PORT_PRI_GRP1r 7408 }; 7409 static const soc_field_t prigroup_field[] = { 7410 PRI0_GRPf, PRI1_GRPf, PRI2_GRPf, PRI3_GRPf, 7411 PRI4_GRPf, PRI5_GRPf, PRI6_GRPf, PRI7_GRPf, 7412 PRI8_GRPf, PRI9_GRPf, PRI10_GRPf, PRI11_GRPf, 7413 PRI12_GRPf, PRI13_GRPf, PRI14_GRPf, PRI15_GRPf 7414 }; 7415 7416 si = &SOC_INFO(unit); 7417 7418 if (!arg) { 7419 return BCM_E_PARAM; 7420 } 7421 7422 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 7423 BCM_IF_ERROR_RETURN 7424 (_bcm_td_cosq_dynamic_thresh_enable_get(unit, gport, cosq, 7425 bcmCosqControlEgressUCSharedDynamicEnable, 7426 &dynamic_thresh_mode)); 7427 if (!dynamic_thresh_mode){ 7428 return BCM_E_CONFIG; 7429 } 7430 7431 BCM_IF_ERROR_RETURN 7432 (_bcm_td_cosq_index_resolve(unit, gport, cosq, 7433 _BCM_TD_COSQ_INDEX_STYLE_UCAST_QUEUE, 7434 &local_port, &startq, NULL)); 7435 BCM_IF_ERROR_RETURN 7436 (_bcm_td_cosq_node_get(unit, gport, NULL, NULL, &id, NULL)); 7437 if (id < _BCM_TD_NUM_UCAST_QUEUE_GROUP) { 7438 /* regular unicast queue */ 7439 if (SOC_PBMP_MEMBER(si->xpipe_pbm, local_port)) { /* X pipe */ 7440 mem = MMU_THDO_CONFIG_0m; 7441 } else { /* Y pipe */ 7442 mem = MMU_THDO_CONFIG_1m; 7443 } 7444 } else { 7445 /* extended unicast queue */ 7446 if (SOC_PBMP_MEMBER(si->xpipe_pbm, local_port)) { /* X pipe */ 7447 mem = MMU_THDO_CONFIG_EX_0m; 7448 } else { /* Y pipe */ 7449 mem = MMU_THDO_CONFIG_EX_1m; 7450 } 7451 } 7452 BCM_IF_ERROR_RETURN 7453 (soc_mem_read(unit, mem, MEM_BLOCK_ALL, startq, entry)); 7454 alpha = soc_mem_field32_get(unit, mem, entry, Q_SHARED_ALPHA_CELLf); 7455 7456 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 7457 BCM_IF_ERROR_RETURN 7458 (_bcm_td_cosq_dynamic_thresh_enable_get(unit, gport, cosq, 7459 bcmCosqControlEgressMCSharedDynamicEnable, 7460 &dynamic_thresh_mode)); 7461 if (!dynamic_thresh_mode){ 7462 return BCM_E_CONFIG; 7463 } 7464 7465 BCM_IF_ERROR_RETURN 7466 (_bcm_td_cosq_index_resolve(unit, gport, cosq, 7467 _BCM_TD_COSQ_INDEX_STYLE_MCAST_QUEUE, 7468 &local_port, &startq, NULL)); 7469 BCM_IF_ERROR_RETURN 7470 (READ_OP_QUEUE_CONFIG_CELLr(unit, local_port, cosq, &rval)); 7471 alpha = soc_reg_field_get(unit, OP_QUEUE_CONFIG_CELLr, rval, 7472 Q_SHARED_ALPHA_CELLf); 7473 7474 } else { 7475 BCM_IF_ERROR_RETURN 7476 (_bcm_td_cosq_dynamic_thresh_enable_get(unit, gport, cosq, 7477 bcmCosqControlIngressPortPGSharedDynamicEnable, 7478 &dynamic_thresh_mode)); 7479 if (!dynamic_thresh_mode){ 7480 return BCM_E_CONFIG; 7481 } 7482 7483 BCM_IF_ERROR_RETURN 7484 (_bcm_td_cosq_localport_resolve(unit, gport, &local_port)); 7485 if (local_port < 0) { 7486 return BCM_E_PORT; 7487 } 7488 7489 /* get PG for port using Port+Cos */ 7490 if (cosq < 8) { 7491 reg = prigroup_reg[0]; 7492 } else { 7493 reg = prigroup_reg[1]; 7494 } 7495 7496 SOC_IF_ERROR_RETURN 7497 (soc_reg32_get(unit, reg, local_port, 0, &rval)); 7498 port_pg = soc_reg_field_get(unit, reg, rval, prigroup_field[cosq]); 7499 7500 SOC_IF_ERROR_RETURN 7501 (READ_PG_SHARED_LIMIT_CELLr(unit, local_port, port_pg, &rval)); 7502 alpha = soc_reg_field_get(unit, PG_SHARED_LIMIT_CELLr, rval, 7503 PG_SHARED_LIMITf); 7504 } 7505 7506 switch(alpha) { 7507 case SOC_TD_COSQ_DROP_LIMIT_ALPHA_1_64: 7508 *arg = bcmCosqControlDropLimitAlpha_1_64; 7509 break; 7510 case SOC_TD_COSQ_DROP_LIMIT_ALPHA_1_32: 7511 *arg = bcmCosqControlDropLimitAlpha_1_32; 7512 break; 7513 case SOC_TD_COSQ_DROP_LIMIT_ALPHA_1_16: 7514 *arg = bcmCosqControlDropLimitAlpha_1_16; 7515 break; 7516 case SOC_TD_COSQ_DROP_LIMIT_ALPHA_1_8: 7517 *arg = bcmCosqControlDropLimitAlpha_1_8; 7518 break; 7519 case SOC_TD_COSQ_DROP_LIMIT_ALPHA_1_4: 7520 *arg = bcmCosqControlDropLimitAlpha_1_4; 7521 break; 7522 case SOC_TD_COSQ_DROP_LIMIT_ALPHA_1_2: 7523 *arg = bcmCosqControlDropLimitAlpha_1_2; 7524 break; 7525 case SOC_TD_COSQ_DROP_LIMIT_ALPHA_1: 7526 *arg = bcmCosqControlDropLimitAlpha_1; 7527 break; 7528 case SOC_TD_COSQ_DROP_LIMIT_ALPHA_2: 7529 *arg = bcmCosqControlDropLimitAlpha_2; 7530 break; 7531 case SOC_TD_COSQ_DROP_LIMIT_ALPHA_4: 7532 *arg = bcmCosqControlDropLimitAlpha_4; 7533 break; 7534 case SOC_TD_COSQ_DROP_LIMIT_ALPHA_8: 7535 *arg = bcmCosqControlDropLimitAlpha_8; 7536 break; 7537 default: 7538 return BCM_E_PARAM; 7539 } 7540 7541 return BCM_E_NONE; 7542 } 7543 7544 STATIC int 7545 _bcm_td_cosq_dynamic_thresh_enable_set(int unit, 7546 bcm_gport_t gport, bcm_cos_queue_t cosq, 7547 bcm_cosq_control_t type, int arg) 7548 { 7549 bcm_port_t local_port; 7550 int id,startq; 7551 uint32 entry[SOC_MAX_MEM_WORDS]; 7552 soc_mem_t mem = INVALIDm; 7553 soc_info_t *si; 7554 uint32 rval; 7555 int port_pg; 7556 soc_reg_t reg = INVALIDr; 7557 static const soc_reg_t prigroup_reg[] = { 7558 PORT_PRI_GRP0r, PORT_PRI_GRP1r 7559 }; 7560 static const soc_field_t prigroup_field[] = { 7561 PRI0_GRPf, PRI1_GRPf, PRI2_GRPf, PRI3_GRPf, 7562 PRI4_GRPf, PRI5_GRPf, PRI6_GRPf, PRI7_GRPf, 7563 PRI8_GRPf, PRI9_GRPf, PRI10_GRPf, PRI11_GRPf, 7564 PRI12_GRPf, PRI13_GRPf, PRI14_GRPf, PRI15_GRPf 7565 }; 7566 7567 si = &SOC_INFO(unit); 7568 7569 if (type == bcmCosqControlIngressPortPGSharedDynamicEnable) { 7570 BCM_IF_ERROR_RETURN 7571 (_bcm_td_cosq_localport_resolve(unit, gport, &local_port)); 7572 if (local_port < 0) { 7573 return BCM_E_PORT; 7574 } 7575 if ((cosq < 0) || (cosq >= 16)) { 7576 return BCM_E_PARAM; 7577 } 7578 7579 /* get PG for port using Port+Cos */ 7580 if (cosq < 8) { 7581 reg = prigroup_reg[0]; 7582 } else { 7583 reg = prigroup_reg[1]; 7584 } 7585 7586 SOC_IF_ERROR_RETURN 7587 (soc_reg32_get(unit, reg, local_port, 0, &rval)); 7588 port_pg = soc_reg_field_get(unit, reg, rval, prigroup_field[cosq]); 7589 7590 SOC_IF_ERROR_RETURN 7591 (READ_PG_SHARED_LIMIT_CELLr(unit, local_port, port_pg, &rval)); 7592 soc_reg_field_set(unit, PG_SHARED_LIMIT_CELLr, &rval, 7593 PG_SHARED_DYNAMICf, arg ? 1 : 0); 7594 SOC_IF_ERROR_RETURN 7595 (WRITE_PG_SHARED_LIMIT_CELLr(unit, local_port, port_pg, rval)); 7596 } else if (type == bcmCosqControlEgressUCSharedDynamicEnable) { 7597 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 7598 BCM_IF_ERROR_RETURN 7599 (_bcm_td_cosq_index_resolve(unit, gport, cosq, 7600 _BCM_TD_COSQ_INDEX_STYLE_UCAST_QUEUE, 7601 &local_port, &startq, NULL)); 7602 7603 BCM_IF_ERROR_RETURN 7604 (_bcm_td_cosq_node_get(unit, gport, NULL, NULL, &id, NULL)); 7605 if (id < _BCM_TD_NUM_UCAST_QUEUE_GROUP) { 7606 /* regular unicast queue */ 7607 if (SOC_PBMP_MEMBER(si->xpipe_pbm, local_port)) { /* X pipe */ 7608 mem = MMU_THDO_CONFIG_0m; 7609 } else { /* Y pipe */ 7610 mem = MMU_THDO_CONFIG_1m; 7611 } 7612 } else { 7613 /* extended unicast queue */ 7614 if (SOC_PBMP_MEMBER(si->xpipe_pbm, local_port)) { /* X pipe */ 7615 mem = MMU_THDO_CONFIG_EX_0m; 7616 } else { /* Y pipe */ 7617 mem = MMU_THDO_CONFIG_EX_1m; 7618 } 7619 } 7620 BCM_IF_ERROR_RETURN 7621 (soc_mem_read(unit, mem, MEM_BLOCK_ALL, startq, entry)); 7622 soc_mem_field32_set(unit, mem, entry, 7623 Q_LIMIT_DYNAMIC_CELLf, arg ? 1 : 0); 7624 SOC_IF_ERROR_RETURN 7625 (soc_mem_write(unit, mem, MEM_BLOCK_ALL, startq, entry)); 7626 7627 } else { 7628 return BCM_E_PARAM; 7629 } 7630 } else if (type == bcmCosqControlEgressMCSharedDynamicEnable) { 7631 if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 7632 BCM_IF_ERROR_RETURN 7633 (_bcm_td_cosq_index_resolve(unit, gport, cosq, 7634 _BCM_TD_COSQ_INDEX_STYLE_MCAST_QUEUE, 7635 &local_port, &startq, NULL)); 7636 BCM_IF_ERROR_RETURN 7637 (READ_OP_QUEUE_CONFIG1_CELLr(unit, local_port, cosq, &rval)); 7638 soc_reg_field_set(unit, OP_QUEUE_CONFIG1_CELLr, &rval, 7639 Q_LIMIT_DYNAMIC_CELLf, arg ? 1 : 0); 7640 BCM_IF_ERROR_RETURN 7641 (WRITE_OP_QUEUE_CONFIG1_CELLr(unit, local_port, cosq, rval)); 7642 7643 } else { 7644 return BCM_E_PARAM; 7645 } 7646 7647 } else { 7648 return BCM_E_PARAM; 7649 } 7650 7651 /* Set default alpha value*/ 7652 if (arg) { 7653 BCM_IF_ERROR_RETURN 7654 (_bcm_td_cosq_alpha_set(unit, gport, cosq, 7655 bcmCosqControlDropLimitAlpha_1_64)); 7656 } 7657 7658 return BCM_E_NONE; 7659 } 7660 7661 STATIC int 7662 _bcm_td_cosq_dynamic_thresh_enable_get(int unit, 7663 bcm_gport_t gport, bcm_cos_queue_t cosq, 7664 bcm_cosq_control_t type, int *arg) 7665 { 7666 bcm_port_t local_port; 7667 int id,startq; 7668 uint32 entry[SOC_MAX_MEM_WORDS]; 7669 soc_mem_t mem = INVALIDm; 7670 soc_info_t *si; 7671 uint32 rval; 7672 int port_pg; 7673 soc_reg_t reg = INVALIDr; 7674 static const soc_reg_t prigroup_reg[] = { 7675 PORT_PRI_GRP0r, PORT_PRI_GRP1r 7676 }; 7677 static const soc_field_t prigroup_field[] = { 7678 PRI0_GRPf, PRI1_GRPf, PRI2_GRPf, PRI3_GRPf, 7679 PRI4_GRPf, PRI5_GRPf, PRI6_GRPf, PRI7_GRPf, 7680 PRI8_GRPf, PRI9_GRPf, PRI10_GRPf, PRI11_GRPf, 7681 PRI12_GRPf, PRI13_GRPf, PRI14_GRPf, PRI15_GRPf 7682 }; 7683 7684 si = &SOC_INFO(unit); 7685 7686 if (type == bcmCosqControlIngressPortPGSharedDynamicEnable) { 7687 BCM_IF_ERROR_RETURN 7688 (_bcm_td_cosq_localport_resolve(unit, gport, &local_port)); 7689 if (local_port < 0) { 7690 return BCM_E_PORT; 7691 } 7692 if ((cosq < 0) || (cosq >= 16)) { 7693 return BCM_E_PARAM; 7694 } 7695 7696 /* get PG for port using Port+Cos */ 7697 if (cosq < 8) { 7698 reg = prigroup_reg[0]; 7699 } else { 7700 reg = prigroup_reg[1]; 7701 } 7702 7703 SOC_IF_ERROR_RETURN 7704 (soc_reg32_get(unit, reg, local_port, 0, &rval)); 7705 port_pg = soc_reg_field_get(unit, reg, rval, prigroup_field[cosq]); 7706 7707 SOC_IF_ERROR_RETURN 7708 (READ_PG_SHARED_LIMIT_CELLr(unit, local_port, port_pg, &rval)); 7709 *arg = soc_reg_field_get(unit, PG_SHARED_LIMIT_CELLr, rval, 7710 PG_SHARED_DYNAMICf); 7711 } else if (type == bcmCosqControlEgressUCSharedDynamicEnable) { 7712 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 7713 BCM_IF_ERROR_RETURN 7714 (_bcm_td_cosq_index_resolve(unit, gport, cosq, 7715 _BCM_TD_COSQ_INDEX_STYLE_UCAST_QUEUE, 7716 &local_port, &startq, NULL)); 7717 7718 BCM_IF_ERROR_RETURN 7719 (_bcm_td_cosq_node_get(unit, gport, NULL, NULL, &id, NULL)); 7720 if (id < _BCM_TD_NUM_UCAST_QUEUE_GROUP) { 7721 /* regular unicast queue */ 7722 if (SOC_PBMP_MEMBER(si->xpipe_pbm, local_port)) { /* X pipe */ 7723 mem = MMU_THDO_CONFIG_0m; 7724 } else { /* Y pipe */ 7725 mem = MMU_THDO_CONFIG_1m; 7726 } 7727 } else { 7728 /* extended unicast queue */ 7729 if (SOC_PBMP_MEMBER(si->xpipe_pbm, local_port)) { /* X pipe */ 7730 mem = MMU_THDO_CONFIG_EX_0m; 7731 } else { /* Y pipe */ 7732 mem = MMU_THDO_CONFIG_EX_1m; 7733 } 7734 } 7735 BCM_IF_ERROR_RETURN 7736 (soc_mem_read(unit, mem, MEM_BLOCK_ALL, startq, entry)); 7737 *arg = soc_mem_field32_get(unit, mem, entry, Q_LIMIT_DYNAMIC_CELLf); 7738 7739 } else { 7740 return BCM_E_PARAM; 7741 } 7742 } else if (type == bcmCosqControlEgressMCSharedDynamicEnable) { 7743 if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 7744 BCM_IF_ERROR_RETURN 7745 (_bcm_td_cosq_index_resolve(unit, gport, cosq, 7746 _BCM_TD_COSQ_INDEX_STYLE_MCAST_QUEUE, 7747 &local_port, &startq, NULL)); 7748 BCM_IF_ERROR_RETURN 7749 (READ_OP_QUEUE_CONFIG1_CELLr(unit, local_port, cosq, &rval)); 7750 *arg = soc_reg_field_get(unit, OP_QUEUE_CONFIG1_CELLr, rval, 7751 Q_LIMIT_DYNAMIC_CELLf); 7752 7753 } else { 7754 return BCM_E_PARAM; 7755 } 7756 } else { 7757 return BCM_E_PARAM; 7758 } 7759 7760 return BCM_E_NONE; 7761 } 7762 7763 STATIC int 7764 _bcm_td_cosq_egr_queue_set(int unit, bcm_gport_t gport, bcm_cos_queue_t cosq, 7765 bcm_cosq_control_t type, int arg) 7766 { 7767 bcm_port_t local_port; 7768 int id, startq; 7769 uint32 entry[SOC_MAX_MEM_WORDS]; 7770 soc_mem_t mem = INVALIDm; 7771 soc_info_t *si; 7772 int granularity = 1; 7773 uint32 rval, rval2; 7774 int phy_port, mmu_port; 7775 7776 if (arg < 0) { 7777 return BCM_E_PARAM; 7778 } 7779 7780 si = &SOC_INFO(unit); 7781 7782 arg /= _BCM_TD_BYTES_PER_CELL; 7783 7784 if ((type == bcmCosqControlEgressUCQueueMinLimitBytes) || 7785 (type == bcmCosqControlEgressUCQueueSharedLimitBytes)) { 7786 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 7787 BCM_IF_ERROR_RETURN 7788 (_bcm_td_cosq_index_resolve(unit, gport, cosq, 7789 _BCM_TD_COSQ_INDEX_STYLE_UCAST_QUEUE, 7790 &local_port, NULL, NULL)); 7791 BCM_IF_ERROR_RETURN 7792 (_bcm_td_cosq_node_get(unit, gport, NULL, NULL, &id, NULL)); 7793 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 7794 return BCM_E_PARAM; 7795 } else { 7796 if (cosq == BCM_COS_INVALID) { 7797 return BCM_E_PARAM; 7798 } 7799 BCM_IF_ERROR_RETURN 7800 (_bcm_td_cosq_localport_resolve(unit, gport, &local_port)); 7801 if (local_port < 0) { 7802 return BCM_E_PORT; 7803 } 7804 id = cosq; 7805 } 7806 7807 phy_port = si->port_l2p_mapping[local_port]; 7808 mmu_port = si->port_p2m_mapping[phy_port]; 7809 7810 /* regular unicast queue */ 7811 if (si->port_num_ext_cosq[local_port] == 0) { 7812 /* Front-panel ports */ 7813 if (SOC_PBMP_MEMBER(si->xpipe_pbm, local_port)) { /* X pipe */ 7814 mem = MMU_THDO_CONFIG_0m; 7815 startq = (mmu_port - 5) * 10 + id; 7816 } else { /* Y pipe */ 7817 mem = MMU_THDO_CONFIG_1m; 7818 startq = (mmu_port - 38) * 10 + id; 7819 } 7820 } else { 7821 /* extended queue ports: 7822 * use MMU_THDO_CONFIG_EX_x table, 74 entries per port 7823 * extended unicast queues: index 0-63 7824 * regular unicast queue: index 64-73 7825 */ 7826 if (SOC_PBMP_MEMBER(si->xpipe_pbm, local_port)) { /* X pipe */ 7827 mem = MMU_THDO_CONFIG_EX_0m; 7828 startq = (mmu_port - 1) * 74 + 64 + id; 7829 } else { /* Y pipe */ 7830 mem = MMU_THDO_CONFIG_EX_1m; 7831 startq = (mmu_port - 34) * 74 + 64 + id; 7832 } 7833 } 7834 7835 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ALL, startq, entry)); 7836 7837 if (type == bcmCosqControlEgressUCQueueSharedLimitBytes) { 7838 soc_mem_field32_set(unit, mem, entry, Q_SHARED_LIMIT_CELLf, (arg/granularity)); 7839 soc_mem_field32_set(unit, mem, entry, Q_LIMIT_ENABLE_CELLf, 1); 7840 soc_mem_field32_set(unit, mem, entry, Q_LIMIT_DYNAMIC_CELLf, 0); 7841 } else { 7842 soc_mem_field32_set(unit, mem, entry, Q_MIN_CELLf, (arg/granularity)); 7843 } 7844 7845 BCM_IF_ERROR_RETURN(soc_mem_write(unit, mem, MEM_BLOCK_ALL, startq, entry)); 7846 } else if ((type == bcmCosqControlEgressMCQueueMinLimitBytes) || 7847 (type == bcmCosqControlEgressMCQueueSharedLimitBytes)) { 7848 if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 7849 if (cosq != BCM_COS_INVALID) { 7850 return BCM_E_PARAM; 7851 } 7852 BCM_IF_ERROR_RETURN 7853 (_bcm_td_cosq_index_resolve(unit, gport, cosq, 7854 _BCM_TD_COSQ_INDEX_STYLE_MCAST_QUEUE, 7855 &local_port, &startq, NULL)); 7856 } else if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 7857 return BCM_E_PARAM; 7858 } else { 7859 if (cosq == BCM_COS_INVALID) { 7860 return BCM_E_PARAM; 7861 } 7862 BCM_IF_ERROR_RETURN 7863 (_bcm_td_cosq_localport_resolve(unit, gport, &local_port)); 7864 if (local_port < 0) { 7865 return BCM_E_PORT; 7866 } 7867 startq = cosq; 7868 } 7869 BCM_IF_ERROR_RETURN 7870 (READ_OP_QUEUE_CONFIG_CELLr(unit, local_port, startq, &rval)); 7871 if (type == bcmCosqControlEgressMCQueueSharedLimitBytes) { 7872 soc_reg_field_set(unit, OP_QUEUE_CONFIG_CELLr, &rval, 7873 Q_SHARED_LIMIT_CELLf, arg/granularity); 7874 7875 /* enable the queue discard thresholds */ 7876 BCM_IF_ERROR_RETURN 7877 (READ_OP_QUEUE_CONFIG1_CELLr(unit, local_port, startq, &rval2)); 7878 soc_reg_field_set(unit,OP_QUEUE_CONFIG1_CELLr, &rval2, 7879 Q_LIMIT_ENABLE_CELLf, 1); 7880 soc_reg_field_set(unit,OP_QUEUE_CONFIG1_CELLr, &rval2, 7881 Q_LIMIT_DYNAMIC_CELLf, 0); 7882 BCM_IF_ERROR_RETURN 7883 (WRITE_OP_QUEUE_CONFIG1_CELLr(unit, local_port, startq, rval2)); 7884 } else { 7885 soc_reg_field_set(unit, OP_QUEUE_CONFIG_CELLr, &rval, 7886 Q_MIN_CELLf, arg/granularity); 7887 } 7888 BCM_IF_ERROR_RETURN 7889 (WRITE_OP_QUEUE_CONFIG_CELLr(unit, local_port, startq, rval)); 7890 }else { 7891 return BCM_E_PARAM; 7892 } 7893 return BCM_E_NONE; 7894 } 7895 7896 STATIC int 7897 _bcm_td_cosq_egr_queue_get(int unit, bcm_gport_t gport, bcm_cos_queue_t cosq, 7898 bcm_cosq_control_t type, int *arg) 7899 { 7900 bcm_port_t local_port; 7901 int id, startq; 7902 uint32 entry[SOC_MAX_MEM_WORDS]; 7903 soc_mem_t mem = INVALIDm; 7904 soc_info_t *si; 7905 int granularity = 1; 7906 uint32 rval; 7907 int phy_port, mmu_port; 7908 7909 if (arg == NULL) { 7910 return BCM_E_PARAM; 7911 } 7912 7913 si = &SOC_INFO(unit); 7914 7915 if ((type == bcmCosqControlEgressUCQueueMinLimitBytes) || 7916 (type == bcmCosqControlEgressUCQueueSharedLimitBytes)) { 7917 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 7918 BCM_IF_ERROR_RETURN 7919 (_bcm_td_cosq_index_resolve(unit, gport, cosq, 7920 _BCM_TD_COSQ_INDEX_STYLE_UCAST_QUEUE, 7921 &local_port, NULL, NULL)); 7922 BCM_IF_ERROR_RETURN(_bcm_td_cosq_node_get(unit, gport, NULL, NULL, &id, NULL)); 7923 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 7924 return BCM_E_PARAM; 7925 } else { 7926 if (cosq == BCM_COS_INVALID) { 7927 return BCM_E_PARAM; 7928 } 7929 BCM_IF_ERROR_RETURN 7930 (_bcm_td_cosq_localport_resolve(unit, gport, &local_port)); 7931 if (local_port < 0) { 7932 return BCM_E_PORT; 7933 } 7934 id = cosq; 7935 } 7936 7937 phy_port = si->port_l2p_mapping[local_port]; 7938 mmu_port = si->port_p2m_mapping[phy_port]; 7939 7940 /* regular unicast queue */ 7941 if (si->port_num_ext_cosq[local_port] == 0) { 7942 /* Front-panel ports */ 7943 if (SOC_PBMP_MEMBER(si->xpipe_pbm, local_port)) { /* X pipe */ 7944 mem = MMU_THDO_CONFIG_0m; 7945 startq = (mmu_port - 5) * 10 + id; 7946 } else { /* Y pipe */ 7947 mem = MMU_THDO_CONFIG_1m; 7948 startq = (mmu_port - 38) * 10 + id; 7949 } 7950 } else { 7951 /* extended queue ports 7952 * use MMU_THDO_CONFIG_EX_x table, 74 entries per port 7953 * extended unicast queues: index 0-63 7954 * regular unicast queue: index 64-73 7955 */ 7956 if (SOC_PBMP_MEMBER(si->xpipe_pbm, local_port)) { /* X pipe */ 7957 mem = MMU_THDO_CONFIG_EX_0m; 7958 startq = (mmu_port - 1) * 74 + 64 + id; 7959 } else { /* Y pipe */ 7960 mem = MMU_THDO_CONFIG_EX_1m; 7961 startq = (mmu_port - 34) * 74 + 64 + id; 7962 } 7963 } 7964 7965 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ALL, startq, entry)); 7966 if (type == bcmCosqControlEgressUCQueueSharedLimitBytes) { 7967 *arg = soc_mem_field32_get(unit, mem, entry, Q_SHARED_LIMIT_CELLf); 7968 } else { 7969 *arg = soc_mem_field32_get(unit, mem, entry, Q_MIN_CELLf); 7970 } 7971 } else if ((type == bcmCosqControlEgressMCQueueMinLimitBytes) || 7972 (type == bcmCosqControlEgressMCQueueSharedLimitBytes)) { 7973 if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 7974 if (cosq != BCM_COS_INVALID) { 7975 return BCM_E_PARAM; 7976 } 7977 BCM_IF_ERROR_RETURN 7978 (_bcm_td_cosq_index_resolve(unit, gport, cosq, 7979 _BCM_TD_COSQ_INDEX_STYLE_MCAST_QUEUE, 7980 &local_port, &startq, NULL)); 7981 } else if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 7982 return BCM_E_PARAM; 7983 } else { 7984 if (cosq == BCM_COS_INVALID) { 7985 return BCM_E_PARAM; 7986 } 7987 BCM_IF_ERROR_RETURN 7988 (_bcm_td_cosq_localport_resolve(unit, gport, &local_port)); 7989 if (local_port < 0) { 7990 return BCM_E_PORT; 7991 } 7992 startq = cosq; 7993 } 7994 BCM_IF_ERROR_RETURN 7995 (READ_OP_QUEUE_CONFIG_CELLr(unit, local_port, startq, &rval)); 7996 if (type == bcmCosqControlEgressMCQueueMinLimitBytes) { 7997 *arg = soc_reg_field_get(unit, OP_QUEUE_CONFIG_CELLr, rval, 7998 Q_MIN_CELLf); 7999 } else { 8000 *arg = soc_reg_field_get(unit, OP_QUEUE_CONFIG_CELLr, rval, 8001 Q_SHARED_LIMIT_CELLf); 8002 } 8003 }else { 8004 return BCM_E_PARAM; 8005 } 8006 8007 *arg = (*arg) * granularity * _BCM_TD_BYTES_PER_CELL; 8008 return BCM_E_NONE; 8009 } 8010 8011 STATIC int 8012 _bcm_td_cosq_egr_queue_limit_enable_set(int unit, bcm_gport_t gport, 8013 bcm_cos_queue_t cosq, 8014 bcm_cosq_control_t type, 8015 int arg) 8016 { 8017 bcm_port_t local_port; 8018 int id, startq; 8019 uint32 entry[SOC_MAX_MEM_WORDS]; 8020 soc_mem_t mem = INVALIDm; 8021 soc_info_t *si; 8022 uint32 rval; 8023 int phy_port, mmu_port; 8024 8025 if (arg < 0) { 8026 return BCM_E_PARAM; 8027 } 8028 8029 si = &SOC_INFO(unit); 8030 arg = arg ? 1 : 0; 8031 8032 if (type == bcmCosqControlEgressUCQueueLimitEnable) { 8033 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 8034 BCM_IF_ERROR_RETURN 8035 (_bcm_td_cosq_index_resolve(unit, gport, cosq, 8036 _BCM_TD_COSQ_INDEX_STYLE_UCAST_QUEUE, 8037 &local_port, NULL, NULL)); 8038 BCM_IF_ERROR_RETURN(_bcm_td_cosq_node_get(unit, gport, NULL, NULL, &id, NULL)); 8039 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 8040 return BCM_E_PARAM; 8041 } else { 8042 if (cosq == BCM_COS_INVALID) { 8043 return BCM_E_PARAM; 8044 } 8045 BCM_IF_ERROR_RETURN 8046 (_bcm_td_cosq_localport_resolve(unit, gport, &local_port)); 8047 if (local_port < 0) { 8048 return BCM_E_PORT; 8049 } 8050 id = cosq; 8051 } 8052 8053 phy_port = si->port_l2p_mapping[local_port]; 8054 mmu_port = si->port_p2m_mapping[phy_port]; 8055 8056 /* regular unicast queue */ 8057 if (si->port_num_ext_cosq[local_port] == 0) { 8058 /* Front-panel ports */ 8059 if (SOC_PBMP_MEMBER(si->xpipe_pbm, local_port)) { /* X pipe */ 8060 mem = MMU_THDO_CONFIG_0m; 8061 startq = (mmu_port - 5) * 10 + id; 8062 } else { /* Y pipe */ 8063 mem = MMU_THDO_CONFIG_1m; 8064 startq = (mmu_port - 38) * 10 + id; 8065 } 8066 } else { 8067 /* extended queue ports 8068 * use MMU_THDO_CONFIG_EX_x table, 74 entries per port 8069 * extended unicast queues: index 0-63 8070 * regular unicast queue: index 64-73 8071 */ 8072 if (SOC_PBMP_MEMBER(si->xpipe_pbm, local_port)) { /* X pipe */ 8073 mem = MMU_THDO_CONFIG_EX_0m; 8074 startq = (mmu_port - 1) * 74 + 64 + id; 8075 } else { /* Y pipe */ 8076 mem = MMU_THDO_CONFIG_EX_1m; 8077 startq = (mmu_port - 34) * 74 + 64 + id; 8078 } 8079 } 8080 8081 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ALL, startq, entry)); 8082 soc_mem_field32_set(unit, mem, entry, Q_LIMIT_ENABLE_CELLf, arg); 8083 BCM_IF_ERROR_RETURN(soc_mem_write(unit, mem, MEM_BLOCK_ALL, startq, entry)); 8084 } else if (type == bcmCosqControlEgressMCQueueLimitEnable) { 8085 if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 8086 if (cosq != BCM_COS_INVALID) { 8087 return BCM_E_PARAM; 8088 } 8089 BCM_IF_ERROR_RETURN 8090 (_bcm_td_cosq_index_resolve(unit, gport, cosq, 8091 _BCM_TD_COSQ_INDEX_STYLE_MCAST_QUEUE, 8092 &local_port, &startq, NULL)); 8093 } else if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 8094 return BCM_E_PARAM; 8095 } else { 8096 if (cosq == BCM_COS_INVALID) { 8097 return BCM_E_PARAM; 8098 } 8099 BCM_IF_ERROR_RETURN 8100 (_bcm_td_cosq_localport_resolve(unit, gport, &local_port)); 8101 if (local_port < 0) { 8102 return BCM_E_PORT; 8103 } 8104 startq = cosq; 8105 } 8106 /* enable the queue discard thresholds */ 8107 BCM_IF_ERROR_RETURN 8108 (READ_OP_QUEUE_CONFIG1_CELLr(unit, local_port, startq, &rval)); 8109 soc_reg_field_set(unit,OP_QUEUE_CONFIG1_CELLr, &rval, 8110 Q_LIMIT_ENABLE_CELLf, arg); 8111 BCM_IF_ERROR_RETURN 8112 (WRITE_OP_QUEUE_CONFIG1_CELLr(unit, local_port, startq, rval)); 8113 }else { 8114 return BCM_E_PARAM; 8115 } 8116 return BCM_E_NONE; 8117 } 8118 8119 STATIC int 8120 _bcm_td_cosq_egr_queue_limit_enable_get(int unit, bcm_gport_t gport, 8121 bcm_cos_queue_t cosq, 8122 bcm_cosq_control_t type, 8123 int *arg) 8124 { 8125 bcm_port_t local_port; 8126 int id, startq; 8127 uint32 entry[SOC_MAX_MEM_WORDS]; 8128 soc_mem_t mem = INVALIDm; 8129 soc_info_t *si; 8130 uint32 rval; 8131 int phy_port, mmu_port; 8132 8133 if (arg == NULL) { 8134 return BCM_E_PARAM; 8135 } 8136 8137 si = &SOC_INFO(unit); 8138 8139 if (type == bcmCosqControlEgressUCQueueLimitEnable) { 8140 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 8141 BCM_IF_ERROR_RETURN 8142 (_bcm_td_cosq_index_resolve(unit, gport, cosq, 8143 _BCM_TD_COSQ_INDEX_STYLE_UCAST_QUEUE, 8144 &local_port, NULL, NULL)); 8145 BCM_IF_ERROR_RETURN(_bcm_td_cosq_node_get(unit, gport, NULL, NULL, &id, NULL)); 8146 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 8147 return BCM_E_PARAM; 8148 } else { 8149 if (cosq == BCM_COS_INVALID) { 8150 return BCM_E_PARAM; 8151 } 8152 BCM_IF_ERROR_RETURN 8153 (_bcm_td_cosq_localport_resolve(unit, gport, &local_port)); 8154 if (local_port < 0) { 8155 return BCM_E_PORT; 8156 } 8157 id = cosq; 8158 } 8159 8160 phy_port = si->port_l2p_mapping[local_port]; 8161 mmu_port = si->port_p2m_mapping[phy_port]; 8162 8163 /* regular unicast queue */ 8164 if (si->port_num_ext_cosq[local_port] == 0) { 8165 /* Front-panel ports */ 8166 if (SOC_PBMP_MEMBER(si->xpipe_pbm, local_port)) { /* X pipe */ 8167 mem = MMU_THDO_CONFIG_0m; 8168 startq = (mmu_port - 5) * 10 + id; 8169 } else { /* Y pipe */ 8170 mem = MMU_THDO_CONFIG_1m; 8171 startq = (mmu_port - 38) * 10 + id; 8172 } 8173 } else { 8174 /* extended queue ports 8175 * use MMU_THDO_CONFIG_EX_x table, 74 entries per port 8176 * extended unicast queues: index 0-63 8177 * regular unicast queue: index 64-73 8178 */ 8179 if (SOC_PBMP_MEMBER(si->xpipe_pbm, local_port)) { /* X pipe */ 8180 mem = MMU_THDO_CONFIG_EX_0m; 8181 startq = (mmu_port - 1) * 74 + 64 + id; 8182 } else { /* Y pipe */ 8183 mem = MMU_THDO_CONFIG_EX_1m; 8184 startq = (mmu_port - 34) * 74 + 64 + id; 8185 } 8186 } 8187 8188 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ALL, startq, entry)); 8189 *arg = soc_mem_field32_get(unit, mem, entry, Q_LIMIT_ENABLE_CELLf); 8190 } else if (type == bcmCosqControlEgressMCQueueLimitEnable) { 8191 if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 8192 if (cosq != BCM_COS_INVALID) { 8193 return BCM_E_PARAM; 8194 } 8195 BCM_IF_ERROR_RETURN 8196 (_bcm_td_cosq_index_resolve(unit, gport, cosq, 8197 _BCM_TD_COSQ_INDEX_STYLE_MCAST_QUEUE, 8198 &local_port, &startq, NULL)); 8199 } else if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 8200 return BCM_E_PARAM; 8201 } else { 8202 if (cosq == BCM_COS_INVALID) { 8203 return BCM_E_PARAM; 8204 } 8205 BCM_IF_ERROR_RETURN 8206 (_bcm_td_cosq_localport_resolve(unit, gport, &local_port)); 8207 if (local_port < 0) { 8208 return BCM_E_PORT; 8209 } 8210 startq = cosq; 8211 } 8212 8213 BCM_IF_ERROR_RETURN 8214 (READ_OP_QUEUE_CONFIG1_CELLr(unit, local_port, startq, &rval)); 8215 *arg = soc_reg_field_get(unit, OP_QUEUE_CONFIG1_CELLr, rval, 8216 Q_LIMIT_ENABLE_CELLf); 8217 }else { 8218 return BCM_E_PARAM; 8219 } 8220 return BCM_E_NONE; 8221 } 8222 8223 int 8224 bcm_td_cosq_control_set(int unit, bcm_gport_t gport, bcm_cos_queue_t cosq, 8225 bcm_cosq_control_t type, int arg) 8226 { 8227 switch (type) { 8228 case bcmCosqControlEgressPool: 8229 case bcmCosqControlEgressPoolLimitBytes: 8230 case bcmCosqControlEgressPoolYellowLimitBytes: 8231 case bcmCosqControlEgressPoolRedLimitBytes: 8232 case bcmCosqControlEgressPoolLimitEnable: 8233 case bcmCosqControlUCEgressPool: 8234 case bcmCosqControlMCEgressPool: 8235 return _bcm_td_cosq_egr_pool_set(unit, gport, cosq, type, arg); 8236 case bcmCosqControlDropLimitAlpha: 8237 return _bcm_td_cosq_alpha_set(unit, gport, cosq, 8238 (bcm_cosq_control_drop_limit_alpha_value_t)arg); 8239 case bcmCosqControlIngressPortPGSharedDynamicEnable: 8240 case bcmCosqControlEgressUCSharedDynamicEnable: 8241 case bcmCosqControlEgressMCSharedDynamicEnable: 8242 return _bcm_td_cosq_dynamic_thresh_enable_set(unit, gport, cosq, 8243 type, arg); 8244 case bcmCosqControlEgressUCQueueSharedLimitBytes: 8245 case bcmCosqControlEgressMCQueueSharedLimitBytes: 8246 case bcmCosqControlEgressUCQueueMinLimitBytes: 8247 case bcmCosqControlEgressMCQueueMinLimitBytes: 8248 return _bcm_td_cosq_egr_queue_set(unit, gport, cosq, type, arg); 8249 case bcmCosqControlEgressUCQueueLimitEnable: 8250 case bcmCosqControlEgressMCQueueLimitEnable: 8251 return _bcm_td_cosq_egr_queue_limit_enable_set(unit, gport, cosq, 8252 type, arg); 8253 8254 default: 8255 break; 8256 } 8257 8258 return BCM_E_UNAVAIL; 8259 } 8260 8261 int 8262 bcm_td_cosq_control_get(int unit, bcm_gport_t gport, bcm_cos_queue_t cosq, 8263 bcm_cosq_control_t type, int *arg) 8264 { 8265 switch (type) { 8266 case bcmCosqControlEgressPool: 8267 case bcmCosqControlEgressPoolLimitBytes: 8268 case bcmCosqControlEgressPoolYellowLimitBytes: 8269 case bcmCosqControlEgressPoolRedLimitBytes: 8270 case bcmCosqControlEgressPoolLimitEnable: 8271 case bcmCosqControlUCEgressPool: 8272 case bcmCosqControlMCEgressPool: 8273 return _bcm_td_cosq_egr_pool_get(unit, gport, cosq, type, arg); 8274 case bcmCosqControlDropLimitAlpha: 8275 return _bcm_td_cosq_alpha_get(unit, gport, cosq, 8276 (bcm_cosq_control_drop_limit_alpha_value_t *)arg); 8277 case bcmCosqControlIngressPortPGSharedDynamicEnable: 8278 case bcmCosqControlEgressUCSharedDynamicEnable: 8279 case bcmCosqControlEgressMCSharedDynamicEnable: 8280 return _bcm_td_cosq_dynamic_thresh_enable_get(unit, gport, cosq, 8281 type, arg); 8282 case bcmCosqControlEgressUCQueueSharedLimitBytes: 8283 case bcmCosqControlEgressMCQueueSharedLimitBytes: 8284 case bcmCosqControlEgressUCQueueMinLimitBytes: 8285 case bcmCosqControlEgressMCQueueMinLimitBytes: 8286 return _bcm_td_cosq_egr_queue_get(unit, gport, cosq, type, arg); 8287 case bcmCosqControlEgressUCQueueLimitEnable: 8288 case bcmCosqControlEgressMCQueueLimitEnable: 8289 return _bcm_td_cosq_egr_queue_limit_enable_get(unit, gport, cosq, 8290 type, arg); 8291 8292 default: 8293 break; 8294 } 8295 8296 return BCM_E_UNAVAIL; 8297 } 8298 8299 #if 0 8300 STATIC int 8301 _bcm_td_cosq_gport_detach(int unit, bcm_port_t port) 8302 { 8303 soc_info_t *si; 8304 int phy_port, mmu_port; 8305 int cosq, weights[16]; 8306 uint32 rval, fval_hi, fval_lo; 8307 uint64 rval64, fval64; 8308 8309 si = &SOC_INFO(unit); 8310 8311 phy_port = si->port_l2p_mapping[port]; 8312 mmu_port = si->port_p2m_mapping[phy_port]; 8313 8314 /* Detach from physical port */ 8315 BCM_IF_ERROR_RETURN(READ_ING_COS_MODEr(unit, port, &rval)); 8316 soc_reg_field_set(unit, ING_COS_MODEr, &rval, QUEUE_MODEf, 0); 8317 soc_reg_field_set(unit, ING_COS_MODEr, &rval, COS_MODEf, 0); 8318 BCM_IF_ERROR_RETURN(WRITE_ING_COS_MODEr(unit, port, rval)); 8319 8320 if (si->port_group[port] < 2) { 8321 /* X pipe COS_MODE_SEL has 32 ports (mmu port 1-32) */ 8322 BCM_IF_ERROR_RETURN(READ_COS_MODE_Xr(unit, &rval64)); 8323 fval_lo = soc_reg64_field32_get(unit, COS_MODE_Xr, rval64, 8324 COS_MODE_SELf); 8325 fval_lo &= ~(1 << (mmu_port - 1)); 8326 soc_reg64_field32_set(unit, COS_MODE_Xr, &rval64, COS_MODE_SELf, 8327 fval_lo); 8328 BCM_IF_ERROR_RETURN(WRITE_COS_MODE_Xr(unit, rval64)); 8329 } else { 8330 /* Y pipe COS_MODE_SEL has 33 ports (mmu port 33-65) */ 8331 BCM_IF_ERROR_RETURN(READ_COS_MODE_Yr(unit, &rval64)); 8332 fval64 = soc_reg64_field_get(unit, COS_MODE_Yr, rval64, COS_MODE_SELf); 8333 fval_lo = COMPILER_64_LO(fval64); 8334 fval_hi = COMPILER_64_HI(fval64); 8335 if (mmu_port - 33 < 32) { 8336 fval_lo &= ~(1 << (mmu_port - 33)); 8337 } else { 8338 fval_hi &= ~(1 << (mmu_port - 33 - 32)); 8339 } 8340 COMPILER_64_SET(fval64, fval_hi, fval_lo); 8341 soc_reg64_field_set(unit, COS_MODE_Yr, &rval64, COS_MODE_SELf, fval64); 8342 BCM_IF_ERROR_RETURN(WRITe_COS_MODE_Yr(unit, rval64)); 8343 } 8344 8345 8346 /* Clear bandwidth of all Stage1 COSQs */ 8347 8348 for (cosq = 8; cosq < 24; cosq++) { 8349 BCM_IF_ERROR_RETURN(bcm_td_cosq_bucket_set(unit, port, cosq, 0, 0, 0)); 8350 } 8351 8352 /* Clear weights of all Stage1 COSQs */ 8353 for (cosq = 0; cosq < 16; cosq++) { 8354 weights[cosq] = 0; 8355 } 8356 BCM_IF_ERROR_RETURN 8357 (_bcm_td_cosq_sched_set(unit, port, 0, BCM_COSQ_WEIGHTED_ROUND_ROBIN, 8358 16, weights)); 8359 8360 /* Clear weight for S1 output queue */ 8361 cosq = 8; 8362 BCM_IF_ERROR_RETURN(READ_COSWEIGHTSr(unit, port, cosq, &val)); 8363 soc_reg_field_set(unit, COSWEIGHTSr, &val, COSWEIGHTSf, 0); 8364 BCM_IF_ERROR_RETURN(WRITE_COSWEIGHTSr(unit, port, cosq, val)); 8365 8366 /* Clear discard settings for all Stage1 COSQs */ 8367 for (cosq = 8; cosq < 24; cosq++) { 8368 BCM_IF_ERROR_RETURN 8369 (_bcm_td_cosq_wred_set(unit, port, cosq, 8370 BCM_COSQ_DISCARD_COLOR_ALL | 8371 BCM_COSQ_DISCARD_NONTCP, 8372 TD_CELL_FIELD_MAX, 8373 TD_CELL_FIELD_MAX, 100, 0, 8374 TRUE)); 8375 } 8376 8377 _td_sched_num_cosq[unit][port] = 0; 8378 8379 return BCM_E_NONE; 8380 } 8381 #endif 8382 8383 /* 8384 * Function: 8385 * bcm_td_cosq_gport_add 8386 * Purpose: 8387 * Create a cosq gport structure 8388 * Parameters: 8389 * unit - (IN) unit number 8390 * port - (IN) port number 8391 * numq - (IN) number of COS queues 8392 * flags - (IN) flags (BCM_COSQ_GPORT_XXX) 8393 * gport - (OUT) GPORT identifier 8394 * Returns: 8395 * BCM_E_XXX 8396 */ 8397 int 8398 bcm_td_cosq_gport_add(int unit, bcm_gport_t port, int numq, uint32 flags, 8399 bcm_gport_t *gport) 8400 { 8401 soc_info_t *si; 8402 _bcm_td_cosq_port_info_t *port_info; 8403 _bcm_td_cosq_node_t *node; 8404 bcm_module_t local_modid, modid_out; 8405 bcm_port_t local_port, port_out; 8406 int id; 8407 uint32 sched_encap; 8408 8409 LOG_INFO(BSL_LS_BCM_COSQ, 8410 (BSL_META_U(unit, 8411 "bcm_td_cosq_gport_add: unit=%d port=0x%x numq=%d flags=0x%x\n"), 8412 unit, port, numq, flags)); 8413 8414 if (!soc_feature(unit, soc_feature_ets)) { 8415 return BCM_E_UNAVAIL; 8416 } 8417 8418 if (gport == NULL) { 8419 return BCM_E_PARAM; 8420 } 8421 8422 si = &SOC_INFO(unit); 8423 8424 if (_bcm_td_cosq_port_info[unit] == NULL) { 8425 return BCM_E_INIT; 8426 } 8427 8428 BCM_IF_ERROR_RETURN 8429 (_bcm_td_cosq_localport_resolve(unit, port, &local_port)); 8430 8431 if (local_port < 0 || IS_CPU_PORT(unit, local_port) || 8432 IS_LB_PORT(unit, local_port)) { 8433 return BCM_E_PORT; 8434 } 8435 8436 port_info = &_bcm_td_cosq_port_info[unit][local_port]; 8437 switch (flags) { 8438 case BCM_COSQ_GPORT_UCAST_QUEUE_GROUP: 8439 if (numq != 1) { 8440 return BCM_E_PARAM; 8441 } 8442 for (id = 0; id < _BCM_TD_NUM_UCAST_QUEUE_GROUP; id++) { 8443 if (port_info->ucast[id].numq == 0) { 8444 break; 8445 } 8446 } 8447 if (id == _BCM_TD_NUM_UCAST_QUEUE_GROUP) { 8448 return BCM_E_RESOURCE; 8449 } 8450 BCM_GPORT_UCAST_QUEUE_GROUP_SYSQID_SET(*gport, local_port, id); 8451 node = &port_info->ucast[id]; 8452 break; 8453 case BCM_COSQ_GPORT_MCAST_QUEUE_GROUP: 8454 if (numq != 1) { 8455 return BCM_E_PARAM; 8456 } 8457 for (id = 0; id < _BCM_TD_NUM_MCAST_QUEUE_GROUP; id++) { 8458 if (port_info->mcast[id].numq == 0) { 8459 break; 8460 } 8461 } 8462 if (id == _BCM_TD_NUM_MCAST_QUEUE_GROUP) { 8463 return BCM_E_RESOURCE; 8464 } 8465 BCM_GPORT_MCAST_QUEUE_GROUP_SYSQID_SET(*gport, local_port, id); 8466 node = &port_info->mcast[id]; 8467 break; 8468 case BCM_COSQ_GPORT_DESTMOD_UCAST_QUEUE_GROUP: 8469 if (si->port_num_ext_cosq[local_port] == 0) { /* regular port */ 8470 return BCM_E_PARAM; 8471 } 8472 if (numq <= 0 || numq > 4) { 8473 return BCM_E_PARAM; 8474 } 8475 for (id = 0; id < _BCM_TD_NUM_EXT_UCAST_QUEUE_GROUP; id++) { 8476 if (port_info->ext_ucast[id].numq == 0) { 8477 break; 8478 } 8479 } 8480 if (id == _BCM_TD_NUM_EXT_UCAST_QUEUE_GROUP) { 8481 return BCM_E_RESOURCE; 8482 } 8483 BCM_GPORT_UCAST_QUEUE_GROUP_SYSQID_SET 8484 (*gport, local_port, _BCM_TD_NUM_UCAST_QUEUE_GROUP + id); 8485 node = &port_info->ext_ucast[id]; 8486 8487 /* create VOQ profile which maps internal priorities evenly to 8488 * queues */ 8489 SOC_IF_ERROR_RETURN 8490 (_bcm_td_create_default_profile(unit, *gport, numq, 8491 &node->voq_profile)); 8492 8493 break; 8494 case BCM_COSQ_GPORT_SCHEDULER: 8495 case 0: 8496 /* 8497 * Can not validate actual number of cosq until attach time. 8498 * The max number of configurable input: 8499 * S1: 7 (S2.0, S2.1, S2.2, mcast group, multiast SC/QM queue, 8500 * unicast SC queue, unicast QM queue) 8501 * S2: 9 (hardware allows to select up to 9 of the possible 12 input) 8502 * S3: 18 (1 regular ucast queue, 1 mcast queue, 8503 * 16 extended ucast queues) 8504 */ 8505 if (si->port_num_ext_cosq[local_port] == 0) { /* regular port */ 8506 if (numq <= 0 || numq > _BCM_TD_S2_SCHEDULER_NUM_INPUT) { 8507 return BCM_E_PARAM; 8508 } 8509 } else { /* extended queue port */ 8510 if (numq <= 0 || numq > _BCM_TD_EXT_S3_SCHEDULER_NUM_INPUT) { 8511 return BCM_E_PARAM; 8512 } 8513 } 8514 for (id = 0; id < _BCM_TD_NUM_SCHEDULER; id++) { 8515 if (port_info->sched[id].numq == 0) { 8516 break; 8517 } 8518 } 8519 if (id == _BCM_TD_NUM_SCHEDULER) { 8520 return BCM_E_RESOURCE; 8521 } 8522 8523 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &local_modid)); 8524 BCM_IF_ERROR_RETURN 8525 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET, local_modid, 8526 local_port, &modid_out, &port_out)); 8527 sched_encap = (id << 16) | (modid_out << 8) | port_out; 8528 BCM_GPORT_SCHEDULER_SET(*gport, sched_encap); 8529 node = &port_info->sched[id]; 8530 break; 8531 default: 8532 return BCM_E_PARAM; 8533 } 8534 8535 node->gport = *gport; 8536 node->numq = numq; 8537 node->cosq_attached_to = -1; 8538 node->hw_cosq_attached_to = -1; 8539 node->level = 0; 8540 node->parent = NULL; 8541 node->sibling = NULL; 8542 node->child = NULL; 8543 8544 LOG_INFO(BSL_LS_BCM_COSQ, 8545 (BSL_META_U(unit, 8546 " gport=0x%x\n"), 8547 *gport)); 8548 8549 return BCM_E_NONE; 8550 } 8551 8552 STATIC int 8553 _bcm_td_cosq_gport_delete_all(int unit, bcm_gport_t gport) 8554 { 8555 _bcm_td_cosq_node_t *node; 8556 8557 LOG_INFO(BSL_LS_BCM_COSQ, 8558 (BSL_META_U(unit, 8559 "bcm_td_cosq_gport_delete: unit=%d gport=0x%x\n"), 8560 unit, gport)); 8561 8562 if (!soc_feature(unit, soc_feature_ets)) { 8563 return BCM_E_UNAVAIL; 8564 } 8565 8566 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport) || 8567 BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport) || 8568 BCM_GPORT_IS_SCHEDULER(gport)) { 8569 BCM_IF_ERROR_RETURN 8570 (_bcm_td_cosq_node_get(unit, gport, NULL, NULL, NULL, &node)); 8571 if (node->child != NULL) { 8572 BCM_IF_ERROR_RETURN( 8573 _bcm_td_cosq_gport_delete_all(unit, node->child->gport)); 8574 } 8575 if (node->sibling != NULL) { 8576 BCM_IF_ERROR_RETURN( 8577 _bcm_td_cosq_gport_delete_all(unit, node->sibling->gport)); 8578 } 8579 if (node->cosq_attached_to >= 0) { 8580 BCM_IF_ERROR_RETURN( 8581 bcm_td_cosq_gport_detach(unit, node->gport, BCM_GPORT_INVALID, -1)); 8582 } 8583 node->numq = 0; 8584 } else { 8585 return BCM_E_PORT; 8586 } 8587 8588 return BCM_E_NONE; 8589 } 8590 8591 /* 8592 * Function: 8593 * bcm_td_cosq_gport_delete 8594 * Purpose: 8595 * Destroy a cosq gport structure 8596 * Parameters: 8597 * unit - (IN) unit number 8598 * gport - (IN) GPORT identifier 8599 * Returns: 8600 * BCM_E_XXX 8601 */ 8602 int 8603 bcm_td_cosq_gport_delete(int unit, bcm_gport_t gport) 8604 { 8605 _bcm_td_cosq_node_t *node = NULL, *tnode; 8606 _bcm_td_cosq_port_info_t *port_info; 8607 int ii, local_port; 8608 8609 LOG_INFO(BSL_LS_BCM_COSQ, 8610 (BSL_META_U(unit, 8611 "bcm_td_cosq_gport_delete: unit=%d gport=0x%x\n"), 8612 unit, gport)); 8613 8614 if (!soc_feature(unit, soc_feature_ets)) { 8615 return BCM_E_UNAVAIL; 8616 } 8617 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport) || 8618 BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport) || 8619 BCM_GPORT_IS_SCHEDULER(gport)) { 8620 BCM_IF_ERROR_RETURN 8621 (_bcm_td_cosq_node_get(unit, gport, NULL, NULL, NULL, &node)); 8622 8623 if (node->cosq_attached_to >= 0) { 8624 BCM_IF_ERROR_RETURN 8625 (bcm_td_cosq_gport_detach(unit, node->gport, BCM_GPORT_INVALID, -1)); 8626 } 8627 8628 node->numq = 0; 8629 } else { 8630 local_port = (BCM_GPORT_IS_LOCAL(gport)) ? 8631 BCM_GPORT_LOCAL_GET(gport) : BCM_GPORT_MODPORT_PORT_GET(gport); 8632 8633 if (!SOC_PORT_VALID(unit, local_port)) { 8634 return BCM_E_PORT; 8635 } 8636 8637 port_info = &_bcm_td_cosq_port_info[unit][local_port]; 8638 for (ii = 0; ii < _BCM_TD_NUM_SCHEDULER; ii++) { 8639 tnode = &port_info->sched[ii]; 8640 if (port_info->sched[ii].numq == 0) { 8641 continue; 8642 } 8643 /* s1 node */ 8644 if (tnode->level == 1) { 8645 node = tnode; 8646 break; 8647 } 8648 } 8649 if (node == NULL) { 8650 return BCM_E_NONE; 8651 } 8652 BCM_IF_ERROR_RETURN( 8653 _bcm_td_cosq_gport_delete_all(unit, node->gport)); 8654 } 8655 8656 return BCM_E_NONE; 8657 } 8658 8659 /* 8660 * Function: 8661 * bcm_td_cosq_gport_get 8662 * Purpose: 8663 * Get a cosq gport structure 8664 * Parameters: 8665 * unit - (IN) unit number 8666 * gport - (IN) GPORT identifier 8667 * port - (OUT) port number 8668 * numq - (OUT) number of COS queues 8669 * flags - (OUT) flags (BCM_COSQ_GPORT_XXX) 8670 * Returns: 8671 * BCM_E_XXX 8672 */ 8673 int 8674 bcm_td_cosq_gport_get(int unit, bcm_gport_t gport, bcm_gport_t *port, 8675 int *numq, uint32 *flags) 8676 { 8677 _bcm_td_cosq_node_t *node; 8678 bcm_module_t modid; 8679 bcm_port_t local_port; 8680 int id; 8681 _bcm_gport_dest_t dest; 8682 8683 if (port == NULL || numq == NULL || flags == NULL) { 8684 return BCM_E_PARAM; 8685 } 8686 8687 LOG_INFO(BSL_LS_BCM_COSQ, 8688 (BSL_META_U(unit, 8689 "bcm_td_cosq_gport_get: unit=%d gport=0x%x\n"), 8690 unit, gport)); 8691 8692 BCM_IF_ERROR_RETURN 8693 (_bcm_td_cosq_node_get(unit, gport, NULL, &local_port, &id, &node)); 8694 8695 if (SOC_USE_GPORT(unit)) { 8696 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &modid)); 8697 dest.gport_type = _SHR_GPORT_TYPE_MODPORT; 8698 dest.modid = modid; 8699 dest.port = local_port; 8700 BCM_IF_ERROR_RETURN(_bcm_esw_gport_construct(unit, &dest, port)); 8701 } else { 8702 *port = local_port; 8703 } 8704 8705 *numq = node->numq; 8706 8707 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 8708 if (id < _BCM_TD_NUM_UCAST_QUEUE_GROUP) { 8709 *flags = BCM_COSQ_GPORT_UCAST_QUEUE_GROUP; 8710 } else { 8711 *flags = BCM_COSQ_GPORT_DESTMOD_UCAST_QUEUE_GROUP; 8712 } 8713 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(gport)) { 8714 *flags = BCM_COSQ_GPORT_MCAST_QUEUE_GROUP; 8715 } else if (BCM_GPORT_IS_SCHEDULER(gport)) { 8716 *flags = BCM_COSQ_GPORT_SCHEDULER; 8717 } else { 8718 *flags = 0; 8719 } 8720 8721 LOG_INFO(BSL_LS_BCM_COSQ, 8722 (BSL_META_U(unit, 8723 " port=0x%x numq=%d flags=0x%x\n"), 8724 *port, *numq, *flags)); 8725 8726 return BCM_E_NONE; 8727 } 8728 8729 /* 8730 * Function: 8731 * bcm_td_cosq_gport_traverse 8732 * Purpose: 8733 * Walks through the valid COSQ GPORTs and calls 8734 * the user supplied callback function for each entry. 8735 * Parameters: 8736 * unit - (IN) unit number 8737 * trav_fn - (IN) Callback function. 8738 * user_data - (IN) User data to be passed to callback function 8739 * Returns: 8740 * BCM_E_NONE - Success. 8741 * BCM_E_XXX 8742 */ 8743 int 8744 bcm_td_cosq_gport_traverse(int unit, bcm_cosq_gport_traverse_cb cb, 8745 void *user_data) 8746 { 8747 _bcm_td_cosq_port_info_t *port_info; 8748 bcm_module_t my_modid, modid_out; 8749 bcm_port_t port, port_out; 8750 bcm_gport_t gport; 8751 int id, rv = BCM_E_NONE; 8752 8753 if (_bcm_td_cosq_port_info[unit] == NULL) { 8754 return BCM_E_INIT; 8755 } 8756 8757 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &my_modid)); 8758 PBMP_ALL_ITER(unit, port) { 8759 BCM_IF_ERROR_RETURN 8760 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET, 8761 my_modid, port, &modid_out, &port_out)); 8762 BCM_GPORT_MODPORT_SET(gport, modid_out, port_out); 8763 8764 port_info = &_bcm_td_cosq_port_info[unit][port]; 8765 for (id = 0; id < _BCM_TD_NUM_UCAST_QUEUE_GROUP; id++) { 8766 if (port_info->ucast[id].numq == 0) { 8767 continue; 8768 } 8769 /* coverity[value_overwrite] */ 8770 rv = cb(unit, gport, port_info->ucast[id].numq, 8771 BCM_COSQ_GPORT_UCAST_QUEUE_GROUP, 8772 port_info->ucast[id].gport, user_data); 8773 if (BCM_FAILURE(rv)) { 8774 #ifdef BCM_CB_ABORT_ON_ERR 8775 if (SOC_CB_ABORT_ON_ERR(unit)) { 8776 return rv; 8777 } 8778 #endif 8779 } 8780 } 8781 for (id = 0; id < _BCM_TD_NUM_MCAST_QUEUE_GROUP; id++) { 8782 if (port_info->mcast[id].numq == 0) { 8783 continue; 8784 } 8785 /* coverity[value_overwrite] */ 8786 rv = cb(unit, gport, port_info->mcast[id].numq, 8787 BCM_COSQ_GPORT_MCAST_QUEUE_GROUP, 8788 port_info->mcast[id].gport, user_data); 8789 #ifdef BCM_CB_ABORT_ON_ERR 8790 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 8791 return rv; 8792 } 8793 #endif 8794 } 8795 for (id = 0; id < _BCM_TD_NUM_EXT_UCAST_QUEUE_GROUP; id++) { 8796 if (port_info->ext_ucast[id].numq == 0) { 8797 continue; 8798 } 8799 /* coverity[value_overwrite] */ 8800 rv = cb(unit, gport, port_info->ext_ucast[id].numq, 8801 BCM_COSQ_GPORT_UCAST_QUEUE_GROUP, 8802 port_info->ext_ucast[id].gport, user_data); 8803 #ifdef BCM_CB_ABORT_ON_ERR 8804 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 8805 return rv; 8806 } 8807 #endif 8808 } 8809 for (id = 0; id < _BCM_TD_NUM_SCHEDULER; id++) { 8810 if (port_info->sched[id].numq == 0) { 8811 continue; 8812 } 8813 /* coverity[value_overwrite] */ 8814 rv = cb(unit, gport, port_info->sched[id].numq, 8815 BCM_COSQ_GPORT_SCHEDULER, 8816 port_info->sched[id].gport, user_data); 8817 #ifdef BCM_CB_ABORT_ON_ERR 8818 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 8819 return rv; 8820 } 8821 #endif 8822 } 8823 } 8824 8825 return BCM_E_NONE; 8826 } 8827 8828 int 8829 bcm_td_cosq_gport_mapping_set(int unit, bcm_port_t ing_port, 8830 bcm_cos_t int_pri, uint32 flags, 8831 bcm_gport_t gport, bcm_cos_queue_t cosq) 8832 { 8833 return _bcm_td_cosq_mapping_set(unit, ing_port, int_pri, flags, gport, 8834 cosq); 8835 } 8836 8837 int 8838 bcm_td_cosq_gport_mapping_get(int unit, bcm_port_t ing_port, 8839 bcm_cos_t int_pri, uint32 flags, 8840 bcm_gport_t *gport, bcm_cos_queue_t *cosq) 8841 { 8842 if (gport == NULL || cosq == NULL) { 8843 return BCM_E_PARAM; 8844 } 8845 8846 return _bcm_td_cosq_mapping_get(unit, ing_port, int_pri, flags, gport, 8847 cosq); 8848 } 8849 8850 /* 8851 * Function: 8852 * bcm_td_cosq_gport_bandwidth_set 8853 * Purpose: 8854 * Configure COS queue bandwidth control 8855 * Parameters: 8856 * unit - (IN) unit number 8857 * gport - (IN) GPORT identifier 8858 * cosq - (IN) COS queue to configure, -1 for all COS queues 8859 * kbits_sec_min - (IN) minimum bandwidth, kbits/sec 8860 * kbits_sec_max - (IN) maximum bandwidth, kbits/sec 8861 * flags - (IN) BCM_COSQ_BW_* 8862 * Returns: 8863 * BCM_E_XXX 8864 */ 8865 int 8866 bcm_td_cosq_gport_bandwidth_set(int unit, bcm_gport_t gport, 8867 bcm_cos_queue_t cosq, uint32 kbits_sec_min, 8868 uint32 kbits_sec_max, uint32 flags) 8869 { 8870 int numq, i; 8871 8872 if (cosq == -1) { 8873 BCM_IF_ERROR_RETURN 8874 (_bcm_td_cosq_index_resolve(unit, gport, cosq, 8875 _BCM_TD_COSQ_INDEX_STYLE_BUCKET, 8876 NULL, NULL, &numq)); 8877 cosq = 0; 8878 } else { 8879 numq = 1; 8880 } 8881 8882 for (i = 0; i < numq; i++) { 8883 BCM_IF_ERROR_RETURN 8884 (_bcm_td_cosq_bucket_set(unit, gport, cosq + i, kbits_sec_min, 8885 kbits_sec_max, kbits_sec_min, 8886 kbits_sec_max, flags)); 8887 } 8888 8889 return BCM_E_NONE; 8890 } 8891 8892 /* 8893 * Function: 8894 * bcm_td_cosq_gport_bandwidth_get 8895 * Purpose: 8896 * Get COS queue bandwidth control configuration 8897 * Parameters: 8898 * unit - (IN) unit number 8899 * gport - (IN) GPORT identifier 8900 * cosq - (IN) COS queue to get, -1 for any COS queue 8901 * kbits_sec_min - (OUT) minimum bandwidth, kbits/sec 8902 * kbits_sec_max - (OUT) maximum bandwidth, kbits/sec 8903 * flags - (OUT) BCM_COSQ_BW_* 8904 * Returns: 8905 * BCM_E_XXX 8906 */ 8907 int 8908 bcm_td_cosq_gport_bandwidth_get(int unit, bcm_gport_t gport, 8909 bcm_cos_queue_t cosq, uint32 *kbits_sec_min, 8910 uint32 *kbits_sec_max, uint32 *flags) 8911 { 8912 uint32 kbits_sec_burst; 8913 8914 BCM_IF_ERROR_RETURN 8915 (_bcm_td_cosq_bucket_get(unit, gport, cosq == -1 ? 0 : cosq, 8916 kbits_sec_min, kbits_sec_max, 8917 &kbits_sec_burst, &kbits_sec_burst, flags)); 8918 8919 return BCM_E_NONE; 8920 } 8921 8922 /* 8923 * Function: 8924 * bcm_td_cosq_gport_bandwidth_burst_set 8925 * Purpose: 8926 * Configure COS queue bandwidth burst setting 8927 * Parameters: 8928 * unit - (IN) unit number 8929 * gport - (IN) GPORT identifier 8930 * cosq - (IN) COS queue to configure, -1 for all COS queues 8931 * kbits_burst - (IN) maximum burst, kbits 8932 * Returns: 8933 * BCM_E_XXX 8934 */ 8935 int 8936 bcm_td_cosq_gport_bandwidth_burst_set(int unit, bcm_gport_t gport, 8937 bcm_cos_queue_t cosq, 8938 uint32 kbits_burst_min, 8939 uint32 kbits_burst_max) 8940 { 8941 int numq, i; 8942 uint32 kbits_sec_min, kbits_sec_max, kbits_sec_burst, flags = 0; 8943 8944 if (cosq == -1) { 8945 BCM_IF_ERROR_RETURN 8946 (_bcm_td_cosq_index_resolve(unit, gport, cosq, 8947 _BCM_TD_COSQ_INDEX_STYLE_BUCKET, 8948 NULL, NULL, &numq)); 8949 cosq = 0; 8950 } else { 8951 numq = 1; 8952 } 8953 8954 for (i = 0; i < numq; i++) { 8955 BCM_IF_ERROR_RETURN 8956 (_bcm_td_cosq_bucket_get(unit, gport, cosq + i, &kbits_sec_min, 8957 &kbits_sec_max, &kbits_sec_burst, 8958 &kbits_sec_burst, &flags)); 8959 BCM_IF_ERROR_RETURN 8960 (_bcm_td_cosq_bucket_set(unit, gport, cosq + i, kbits_sec_min, 8961 kbits_sec_max, kbits_burst_min, 8962 kbits_burst_max, flags)); 8963 } 8964 8965 return BCM_E_NONE; 8966 } 8967 8968 /* 8969 * Function: 8970 * bcm_td_cosq_gport_bandwidth_burst_get 8971 * Purpose: 8972 * Get COS queue bandwidth burst setting 8973 * Parameters: 8974 * unit - (IN) unit number 8975 * gport - (IN) GPORT identifier 8976 * cosq - (IN) COS queue to get, -1 for any queue 8977 * kbits_burst - (OUT) maximum burst, kbits 8978 * Returns: 8979 * BCM_E_XXX 8980 */ 8981 int 8982 bcm_td_cosq_gport_bandwidth_burst_get(int unit, bcm_gport_t gport, 8983 bcm_cos_queue_t cosq, 8984 uint32 *kbits_burst_min, 8985 uint32 *kbits_burst_max) 8986 { 8987 uint32 kbits_sec_min, kbits_sec_max, flags; 8988 8989 BCM_IF_ERROR_RETURN 8990 (_bcm_td_cosq_bucket_get(unit, gport, cosq == -1 ? 0 : cosq, 8991 &kbits_sec_min, &kbits_sec_max, 8992 kbits_burst_min, kbits_burst_max, &flags)); 8993 8994 return BCM_E_NONE; 8995 } 8996 8997 /* 8998 * Function: 8999 * bcm_td_cosq_gport_sched_set 9000 * Purpose: 9001 * Configure COS queue scheduler setting 9002 * Parameters: 9003 * unit - (IN) unit number 9004 * gport - (IN) GPORT identifier 9005 * cosq - (IN) COS queue to configure, -1 for all COS queues 9006 * mode - (IN) Scheduling mode, one of BCM_COSQ_xxx 9007 * weight - (IN) queue weight 9008 * Returns: 9009 * BCM_E_XXX 9010 */ 9011 int 9012 bcm_td_cosq_gport_sched_set(int unit, bcm_gport_t gport, 9013 bcm_cos_queue_t cosq, int mode, int weight) 9014 { 9015 int rv, numq, i, count; 9016 9017 if (cosq == -1) { 9018 BCM_IF_ERROR_RETURN 9019 (_bcm_td_cosq_index_resolve(unit, gport, cosq, 9020 _BCM_TD_COSQ_INDEX_STYLE_SCHEDULER, 9021 NULL, NULL, &numq)); 9022 cosq = 0; 9023 } else { 9024 numq = 1; 9025 } 9026 9027 count = 0; 9028 for (i = 0; i < numq; i++) { 9029 rv = _bcm_td_cosq_sched_set(unit, gport, cosq + i, mode, 1, &weight); 9030 if (rv == BCM_E_NOT_FOUND) { 9031 continue; 9032 } else if (BCM_FAILURE(rv)) { 9033 return rv; 9034 } else { 9035 count++; 9036 } 9037 } 9038 9039 return count > 0 ? BCM_E_NONE : BCM_E_NOT_FOUND; 9040 } 9041 9042 /* 9043 * Function: 9044 * bcm_td_cosq_gport_sched_get 9045 * Purpose: 9046 * Get COS queue scheduler setting 9047 * Parameters: 9048 * unit - (IN) unit number 9049 * gport - (IN) GPORT identifier 9050 * cosq - (IN) COS queue to get, -1 for any queue 9051 * mode - (OUT) Scheduling mode, one of BCM_COSQ_xxx 9052 * weight - (OUT) queue weight 9053 * Returns: 9054 * BCM_E_XXX 9055 */ 9056 int 9057 bcm_td_cosq_gport_sched_get(int unit, bcm_gport_t gport, bcm_cos_queue_t cosq, 9058 int *mode, int *weight) 9059 { 9060 int rv, numq, i; 9061 9062 if (cosq == -1) { 9063 BCM_IF_ERROR_RETURN 9064 (_bcm_td_cosq_index_resolve(unit, gport, cosq, 9065 _BCM_TD_COSQ_INDEX_STYLE_SCHEDULER, 9066 NULL, NULL, &numq)); 9067 cosq = 0; 9068 } else { 9069 numq = 1; 9070 } 9071 9072 for (i = 0; i < numq; i++) { 9073 rv = _bcm_td_cosq_sched_get(unit, gport, cosq + i, mode, 1, weight); 9074 if (rv == BCM_E_NOT_FOUND) { 9075 continue; 9076 } else { 9077 return rv; 9078 } 9079 } 9080 9081 return BCM_E_NOT_FOUND; 9082 } 9083 9084 /* 9085 * Function: 9086 * bcm_td_cosq_gport_discard_set 9087 * Purpose: 9088 * Configure port WRED setting 9089 * Parameters: 9090 * unit - (IN) unit number 9091 * port - (IN) GPORT identifier 9092 * cosq - (IN) COS queue to configure, -1 for all COS queues 9093 * discard - (IN) discard settings 9094 * Returns: 9095 * BCM_E_XXX 9096 */ 9097 int 9098 bcm_td_cosq_gport_discard_set(int unit, bcm_gport_t gport, 9099 bcm_cos_queue_t cosq, 9100 bcm_cosq_gport_discard_t *discard) 9101 { 9102 int numq, i; 9103 uint32 min_thresh, max_thresh; 9104 int cell_size, cell_field_max; 9105 9106 if (discard == NULL || 9107 discard->gain < 0 || discard->gain > 15 || 9108 discard->drop_probability < 0 || discard->drop_probability > 100 || 9109 (discard->min_thresh > discard->max_thresh) || 9110 (discard->min_thresh < 0)) { 9111 return BCM_E_PARAM; 9112 } 9113 9114 cell_size = _BCM_TD_BYTES_PER_CELL; 9115 cell_field_max = TD_CELL_FIELD_MAX; 9116 9117 min_thresh = discard->min_thresh; 9118 max_thresh = discard->max_thresh; 9119 if (discard->flags & BCM_COSQ_DISCARD_BYTES) { 9120 /* Convert bytes to cells */ 9121 min_thresh += (cell_size - 1); 9122 min_thresh /= cell_size; 9123 9124 max_thresh += (cell_size - 1); 9125 max_thresh /= cell_size; 9126 9127 if ((min_thresh > cell_field_max) || 9128 (max_thresh > cell_field_max)) { 9129 return BCM_E_PARAM; 9130 } 9131 } else { 9132 /* Packet mode not supported */ 9133 return BCM_E_PARAM; 9134 } 9135 9136 if (cosq == -1) { 9137 BCM_IF_ERROR_RETURN 9138 (_bcm_td_cosq_index_resolve(unit, gport, cosq, 9139 _BCM_TD_COSQ_INDEX_STYLE_WRED, 9140 NULL, NULL, &numq)); 9141 cosq = 0; 9142 } else { 9143 numq = 1; 9144 } 9145 9146 for (i = 0; i < numq; i++) { 9147 BCM_IF_ERROR_RETURN 9148 (_bcm_td_cosq_wred_set(unit, gport, cosq + i, discard->flags, 9149 min_thresh, max_thresh, 9150 discard->drop_probability, discard->gain, 9151 FALSE)); 9152 } 9153 9154 return BCM_E_NONE; 9155 } 9156 9157 /* 9158 * Function: 9159 * bcm_td_cosq_gport_discard_get 9160 * Purpose: 9161 * Get port WRED setting 9162 * Parameters: 9163 * unit - (IN) unit number 9164 * port - (IN) GPORT identifier 9165 * cosq - (IN) COS queue to get, -1 for any queue 9166 * discard - (OUT) discard settings 9167 * Returns: 9168 * BCM_E_XXX 9169 */ 9170 int 9171 bcm_td_cosq_gport_discard_get(int unit, bcm_gport_t gport, 9172 bcm_cos_queue_t cosq, 9173 bcm_cosq_gport_discard_t *discard) 9174 { 9175 uint32 min_thresh, max_thresh; 9176 9177 if (discard == NULL) { 9178 return BCM_E_PARAM; 9179 } 9180 9181 BCM_IF_ERROR_RETURN 9182 (_bcm_td_cosq_wred_get(unit, gport, cosq == -1 ? 0 : cosq, 9183 &discard->flags, &min_thresh, &max_thresh, 9184 &discard->drop_probability, &discard->gain)); 9185 9186 /* Convert number of cells to number of bytes */ 9187 discard->min_thresh = min_thresh * _BCM_TD_BYTES_PER_CELL; 9188 discard->max_thresh = max_thresh * _BCM_TD_BYTES_PER_CELL; 9189 9190 return BCM_E_NONE; 9191 } 9192 9193 STATIC int 9194 _bcm_td_cosq_pfc_class_resolve(bcm_switch_control_t sctype, int *type, 9195 int *class) 9196 { 9197 switch (sctype) { 9198 case bcmSwitchPFCClass7Queue: 9199 case bcmSwitchPFCClass6Queue: 9200 case bcmSwitchPFCClass5Queue: 9201 case bcmSwitchPFCClass4Queue: 9202 case bcmSwitchPFCClass3Queue: 9203 case bcmSwitchPFCClass2Queue: 9204 case bcmSwitchPFCClass1Queue: 9205 case bcmSwitchPFCClass0Queue: 9206 *type = _BCM_TD_COSQ_TYPE_UCAST; 9207 break; 9208 case bcmSwitchPFCClass7McastQueue: 9209 case bcmSwitchPFCClass6McastQueue: 9210 case bcmSwitchPFCClass5McastQueue: 9211 case bcmSwitchPFCClass4McastQueue: 9212 case bcmSwitchPFCClass3McastQueue: 9213 case bcmSwitchPFCClass2McastQueue: 9214 case bcmSwitchPFCClass1McastQueue: 9215 case bcmSwitchPFCClass0McastQueue: 9216 *type = _BCM_TD_COSQ_TYPE_MCAST; 9217 break; 9218 case bcmSwitchPFCClass7DestmodQueue: 9219 case bcmSwitchPFCClass6DestmodQueue: 9220 case bcmSwitchPFCClass5DestmodQueue: 9221 case bcmSwitchPFCClass4DestmodQueue: 9222 case bcmSwitchPFCClass3DestmodQueue: 9223 case bcmSwitchPFCClass2DestmodQueue: 9224 case bcmSwitchPFCClass1DestmodQueue: 9225 case bcmSwitchPFCClass0DestmodQueue: 9226 *type = _BCM_TD_COSQ_TYPE_EXT_UCAST; 9227 break; 9228 default: 9229 return BCM_E_PARAM; 9230 } 9231 9232 switch (sctype) { 9233 case bcmSwitchPFCClass7Queue: 9234 case bcmSwitchPFCClass7McastQueue: 9235 case bcmSwitchPFCClass7DestmodQueue: 9236 *class = 7; 9237 break; 9238 case bcmSwitchPFCClass6Queue: 9239 case bcmSwitchPFCClass6McastQueue: 9240 case bcmSwitchPFCClass6DestmodQueue: 9241 *class = 6; 9242 break; 9243 case bcmSwitchPFCClass5Queue: 9244 case bcmSwitchPFCClass5McastQueue: 9245 case bcmSwitchPFCClass5DestmodQueue: 9246 *class = 5; 9247 break; 9248 case bcmSwitchPFCClass4Queue: 9249 case bcmSwitchPFCClass4McastQueue: 9250 case bcmSwitchPFCClass4DestmodQueue: 9251 *class = 4; 9252 break; 9253 case bcmSwitchPFCClass3Queue: 9254 case bcmSwitchPFCClass3McastQueue: 9255 case bcmSwitchPFCClass3DestmodQueue: 9256 *class = 3; 9257 break; 9258 case bcmSwitchPFCClass2Queue: 9259 case bcmSwitchPFCClass2McastQueue: 9260 case bcmSwitchPFCClass2DestmodQueue: 9261 *class = 2; 9262 break; 9263 case bcmSwitchPFCClass1Queue: 9264 case bcmSwitchPFCClass1McastQueue: 9265 case bcmSwitchPFCClass1DestmodQueue: 9266 *class = 1; 9267 break; 9268 case bcmSwitchPFCClass0Queue: 9269 case bcmSwitchPFCClass0McastQueue: 9270 case bcmSwitchPFCClass0DestmodQueue: 9271 *class = 0; 9272 break; 9273 /* 9274 * COVERITY 9275 * 9276 * This default is unreachable but needed for some compiler. 9277 */ 9278 /* coverity[dead_error_begin] */ 9279 default: 9280 return BCM_E_INTERNAL; 9281 } 9282 9283 return BCM_E_NONE; 9284 } 9285 9286 /* 9287 * Function: 9288 * _bcm_td_fc_status_map_gport 9289 * Purpose: 9290 * Update cos_bmp with gport cosq. 9291 * Parameters: 9292 * unit - (IN) unit number 9293 * port - (IN) port number 9294 * type - (IN) cosq type 9295 * gport - (IN) gport to be mapped 9296 * cos_map - (OUT) hw_cosq of gport 9297 * Returns: 9298 * BCM_E_XXX 9299 */ 9300 STATIC int 9301 _bcm_td_fc_status_map_gport(int unit, int port, int type, bcm_gport_t gport, 9302 _bcm_td_cosq_pfc_cos_bmp_t *cos_bmp) 9303 { 9304 bcm_port_t local_port; 9305 bcm_port_t resolved_port; 9306 _bcm_td_cosq_node_t *node; 9307 uint32 uc_bmp, mc_bmp; 9308 int id, cnt; 9309 int ext_uc_count; 9310 int *ext_uc_qid = NULL; 9311 9312 if (NULL == cos_bmp) { 9313 return BCM_E_PARAM; 9314 } 9315 9316 BCM_IF_ERROR_RETURN 9317 (_bcm_td_cosq_localport_resolve(unit, port, &local_port)); 9318 9319 uc_bmp = cos_bmp->uc_bmp; 9320 mc_bmp = cos_bmp->mc_bmp; 9321 ext_uc_count = cos_bmp->ext_uc_count; 9322 ext_uc_qid = &(cos_bmp->ext_uc_qid[0]); 9323 if (BCM_GPORT_IS_SET(gport)) { 9324 if (BCM_GPORT_IS_SCHEDULER(gport)) { 9325 return BCM_E_PORT; 9326 } 9327 9328 BCM_IF_ERROR_RETURN( 9329 _bcm_td_cosq_node_get(unit, gport, NULL, 9330 &resolved_port, &id, &node)); 9331 if (resolved_port != local_port) { 9332 return BCM_E_PORT; 9333 } 9334 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) { 9335 if (id > _BCM_TD_NUM_UCAST_QUEUE_GROUP) { 9336 /* extended unicast queue */ 9337 if (type != _BCM_TD_COSQ_TYPE_EXT_UCAST) { 9338 return BCM_E_PARAM; 9339 } 9340 if (ext_uc_count == _BCM_TD_MAX_NUM_LLFC_EXTQ) { 9341 return BCM_E_RESOURCE; 9342 } 9343 for (cnt = 0; cnt < ext_uc_count; cnt++) { 9344 if (ext_uc_qid[cnt] == node->base + 64) { 9345 break; 9346 } 9347 } 9348 if (cnt == ext_uc_count) { 9349 ext_uc_qid[ext_uc_count] = node->base + 64; 9350 ext_uc_count++; 9351 } 9352 } else { /* unicast queue */ 9353 if (type != _BCM_TD_COSQ_TYPE_UCAST) { 9354 return BCM_E_PARAM; 9355 } 9356 uc_bmp |= 1 << node->base; 9357 } 9358 } else { /* multicast queue */ 9359 if (type != _BCM_TD_COSQ_TYPE_MCAST) { 9360 return BCM_E_PARAM; 9361 } 9362 mc_bmp |= 1 << node->base; 9363 } 9364 } else { 9365 if (type == _BCM_TD_COSQ_TYPE_UCAST) { 9366 bcm_cos_queue_t mc_cosq_max; 9367 mc_cosq_max = (_BCM_TD_NUM_MCAST_QUEUE_GROUP - 1); 9368 uc_bmp |= 1 << gport; 9369 /* In the legacy mode, need to set both UC & MC queue */ 9370 if (gport > mc_cosq_max) { 9371 mc_bmp |= 1 << mc_cosq_max; 9372 } else { 9373 mc_bmp |= 1 << gport; 9374 } 9375 } else { 9376 return BCM_E_PARAM; 9377 } 9378 } 9379 9380 cos_bmp->uc_bmp = uc_bmp; 9381 cos_bmp->mc_bmp = mc_bmp; 9382 cos_bmp->ext_uc_count = ext_uc_count; 9383 9384 return BCM_E_NONE; 9385 } 9386 9387 /* 9388 * Function: 9389 * _bcm_td_port_pfc_profile_set 9390 * Purpose: 9391 * Set PFC mapping profile for port. Updates PRIO2COS_LLFC & PORT_LLFC_CFG. 9392 * Parameters: 9393 * unit - (IN) unit number 9394 * port - (IN) port number 9395 * op - (IN) operation type 9396 * entry_cnt - (IN) count of pfc classes and according bitmaps 9397 * pfc_class - (IN) class list 9398 * cos_bmp - (IN) bmp list 9399 * Returns: 9400 * BCM_E_XXX 9401 */ 9402 STATIC int 9403 _bcm_td_port_pfc_profile_set(int unit, int port, _bcm_cosq_op_t op, 9404 int entry_cnt, int *pfc_class, 9405 _bcm_td_cosq_pfc_cos_bmp_t *cos_bmp) 9406 { 9407 static const soc_field_t valid_field[] = { 9408 Q_VLD0f, Q_VLD1f, Q_VLD2f, Q_VLD3f 9409 }; 9410 static const soc_field_t num_field[] = { 9411 Q_NUM0f, Q_NUM1f, Q_NUM2f, Q_NUM3f 9412 }; 9413 uint32 profile_index, old_profile_index; 9414 uint32 ext_profile_index, ext_old_profile_index; 9415 uint64 rval64[16], *rval64s[1]; 9416 uint64 ext_rval64[16], *ext_rval64s[1]; 9417 uint32 rval, fval; 9418 uint32 uc_bmp, mc_bmp; 9419 int rv, index, id, ext_uc_count, free_index, cur_ext_uc_qid[4]; 9420 int *ext_uc_qid = NULL; 9421 int entry, cur_class, uc_mc_update = 0, euc_update = 0; 9422 9423 rval64s[0] = rval64; 9424 ext_rval64s[0] = ext_rval64; 9425 BCM_IF_ERROR_RETURN(READ_PORT_LLFC_CFGr(unit, port, &rval)); 9426 old_profile_index = soc_reg_field_get(unit, PORT_LLFC_CFGr, rval, 9427 PROFILE_INDEXf) * 16; 9428 BCM_IF_ERROR_RETURN(soc_profile_reg_get(unit, _bcm_td_llfc_profile[unit], 9429 old_profile_index, 16, rval64s)); 9430 ext_old_profile_index = soc_reg_field_get(unit, PORT_LLFC_CFGr, rval, 9431 EXT_PER_Q_INDEXf) * 16; 9432 BCM_IF_ERROR_RETURN 9433 (soc_profile_reg_get(unit, _bcm_td_ext_llfc_profile[unit], 9434 ext_old_profile_index, 16, ext_rval64s)); 9435 9436 for (entry = 0; entry < entry_cnt; entry++) { 9437 cur_class = pfc_class[entry]; 9438 uc_bmp = cos_bmp[entry].uc_bmp; 9439 mc_bmp = cos_bmp[entry].mc_bmp; 9440 ext_uc_count = cos_bmp[entry].ext_uc_count; 9441 ext_uc_qid = &(cos_bmp[entry].ext_uc_qid[0]); 9442 9443 if (uc_bmp != 0 || mc_bmp != 0) { 9444 if (uc_bmp != 0) { 9445 /* coverity[dead_error_condition : FALSE] */ 9446 if (op == _BCM_COSQ_OP_SET) { 9447 fval = uc_bmp; 9448 } else { 9449 fval = soc_reg64_field32_get(unit, PRIO2COS_LLFCr, 9450 rval64[cur_class], 9451 UC_COS0_10_BMPf); 9452 if (op == _BCM_COSQ_OP_ADD) { 9453 fval |= uc_bmp; 9454 } else { /* _BCM_COSQ_OP_DELETE */ 9455 fval &= ~uc_bmp; 9456 } 9457 } 9458 soc_reg64_field32_set(unit, PRIO2COS_LLFCr, &rval64[cur_class], 9459 UC_COS0_10_BMPf, fval); 9460 } 9461 if (mc_bmp != 0) { 9462 if (op == _BCM_COSQ_OP_SET) { 9463 fval = mc_bmp; 9464 } else { 9465 fval = soc_reg64_field32_get(unit, PRIO2COS_LLFCr, 9466 rval64[cur_class], 9467 MC_COS0_5_BMPf); 9468 if (op == _BCM_COSQ_OP_ADD) { 9469 fval |= mc_bmp; 9470 } else { /* _BCM_COSQ_OP_DELETE */ 9471 fval &= ~mc_bmp; 9472 } 9473 } 9474 soc_reg64_field32_set(unit, PRIO2COS_LLFCr, &rval64[cur_class], 9475 MC_COS0_5_BMPf, fval); 9476 } 9477 uc_mc_update = 1; 9478 } 9479 9480 if (ext_uc_count != 0) { 9481 if (op == _BCM_COSQ_OP_SET) { 9482 COMPILER_64_ZERO(ext_rval64[cur_class]); 9483 for (index = 0; index < ext_uc_count; index++) { 9484 soc_reg64_field32_set(unit, PRIO2EXTQ_LLFCr, 9485 &ext_rval64[cur_class], 9486 valid_field[index], 1); 9487 soc_reg64_field32_set(unit, PRIO2EXTQ_LLFCr, 9488 &ext_rval64[cur_class], 9489 num_field[index], ext_uc_qid[index]); 9490 } 9491 } else { 9492 for (id = 0; id < sizeof(num_field) / sizeof(num_field[0]); 9493 id++) { 9494 cur_ext_uc_qid[id] = -1; 9495 if (soc_reg64_field32_get(unit, PRIO2EXTQ_LLFCr, 9496 ext_rval64[cur_class], 9497 valid_field[id])) { 9498 cur_ext_uc_qid[id] = 9499 soc_reg64_field32_get(unit, PRIO2EXTQ_LLFCr, 9500 ext_rval64[cur_class], 9501 num_field[id]); 9502 } 9503 } 9504 if (op == _BCM_COSQ_OP_ADD) { 9505 free_index = -1; 9506 for (index = 0; index < ext_uc_count; index++) { 9507 for (id = 0; 9508 id < sizeof(num_field) / sizeof(num_field[0]); 9509 id++) { 9510 if (ext_uc_qid[index] == cur_ext_uc_qid[id]) { 9511 /* already exist */ 9512 break; 9513 } 9514 if (free_index == -1 && cur_ext_uc_qid[id] == -1) { 9515 free_index = id; 9516 } 9517 } 9518 if (id < sizeof(num_field) / sizeof(num_field[0])) { 9519 continue; 9520 } 9521 soc_reg64_field32_set(unit, PRIO2EXTQ_LLFCr, 9522 &ext_rval64[cur_class], 9523 valid_field[free_index], 1); 9524 soc_reg64_field32_set(unit, PRIO2EXTQ_LLFCr, 9525 &ext_rval64[cur_class], 9526 num_field[free_index], 9527 ext_uc_qid[index]); 9528 } 9529 } else { /* _BCM_COSQ_OP_DELETE */ 9530 for (index = 0; index < ext_uc_count; index++) { 9531 for (id = 0; 9532 id < sizeof(num_field) / sizeof(num_field[0]); 9533 id++) { 9534 if (ext_uc_qid[index] == cur_ext_uc_qid[id]) { 9535 soc_reg64_field32_set(unit, PRIO2EXTQ_LLFCr, 9536 &ext_rval64[cur_class], 9537 valid_field[id], 0); 9538 break; 9539 } 9540 } 9541 } 9542 } 9543 } 9544 euc_update = 1; 9545 } 9546 } 9547 9548 if (uc_mc_update) { 9549 BCM_IF_ERROR_RETURN 9550 (soc_profile_reg_delete(unit, _bcm_td_llfc_profile[unit], 9551 old_profile_index)); 9552 rv = soc_profile_reg_add(unit, _bcm_td_llfc_profile[unit], rval64s, 9553 16, &profile_index); 9554 if (SOC_FAILURE(rv)) { 9555 BCM_IF_ERROR_RETURN 9556 (soc_profile_reg_reference(unit, _bcm_td_llfc_profile[unit], 9557 old_profile_index, 16)); 9558 return rv; 9559 } 9560 soc_reg_field_set(unit, PORT_LLFC_CFGr, &rval, PROFILE_INDEXf, 9561 profile_index / 16); 9562 } 9563 if (euc_update) { 9564 BCM_IF_ERROR_RETURN 9565 (soc_profile_reg_delete(unit, _bcm_td_ext_llfc_profile[unit], 9566 ext_old_profile_index)); 9567 rv = soc_profile_reg_add(unit, _bcm_td_ext_llfc_profile[unit], 9568 ext_rval64s, 16, &ext_profile_index); 9569 if (SOC_FAILURE(rv)) { 9570 BCM_IF_ERROR_RETURN 9571 (soc_profile_reg_reference(unit, _bcm_td_ext_llfc_profile[unit], 9572 ext_old_profile_index, 16)); 9573 return rv; 9574 } 9575 soc_reg_field_set(unit, PORT_LLFC_CFGr, &rval, EXT_PER_Q_INDEXf, 9576 ext_profile_index / 16); 9577 } 9578 BCM_IF_ERROR_RETURN(WRITE_PORT_LLFC_CFGr(unit, port, rval)); 9579 9580 return BCM_E_NONE; 9581 } 9582 9583 int 9584 bcm_td_cosq_port_pfc_op(int unit, bcm_port_t port, 9585 bcm_switch_control_t sctype, _bcm_cosq_op_t op, 9586 bcm_gport_t *gport, int gport_count) 9587 { 9588 _bcm_td_cosq_pfc_cos_bmp_t cos_bmp; 9589 int type = -1, class = -1, index; 9590 9591 if (IS_CPU_PORT(unit, port)) { 9592 return BCM_E_PORT; 9593 } 9594 if (gport_count < 0) { 9595 return BCM_E_PARAM; 9596 } 9597 9598 BCM_IF_ERROR_RETURN(_bcm_td_cosq_pfc_class_resolve(sctype, &type, &class)); 9599 9600 sal_memset(&cos_bmp, 0, sizeof(cos_bmp)); 9601 for (index = 0; index < gport_count; index++) { 9602 if (!BCM_GPORT_IS_SET(gport[index]) && (_BCM_COSQ_OP_CLEAR != op) && 9603 (gport[index] < 0 || gport[index] >= _BCM_TD_NUM_UCAST_QUEUE_GROUP) 9604 ) { 9605 return BCM_E_PARAM; 9606 } 9607 BCM_IF_ERROR_RETURN( 9608 _bcm_td_fc_status_map_gport(unit, port, type, gport[index], 9609 &cos_bmp)); 9610 } 9611 9612 if (op == _BCM_COSQ_OP_CLEAR) { 9613 cos_bmp.uc_bmp = (1 << _BCM_TD_NUM_UCAST_QUEUE_GROUP) - 1; 9614 cos_bmp.mc_bmp = (1 << _BCM_TD_NUM_MCAST_QUEUE_GROUP) - 1; 9615 } 9616 9617 BCM_IF_ERROR_RETURN(_bcm_td_port_pfc_profile_set(unit, port, op, 9618 1, &class, &cos_bmp)); 9619 9620 return BCM_E_NONE; 9621 } 9622 9623 int 9624 bcm_td_cosq_port_pfc_get(int unit, bcm_port_t port, 9625 bcm_switch_control_t sctype, 9626 bcm_gport_t *gport, int gport_count, 9627 int *actual_gport_count) 9628 { 9629 _bcm_td_cosq_port_info_t *port_info; 9630 bcm_port_t local_port; 9631 int type = -1, class = -1, id, hw_cosq, count, i; 9632 static const soc_field_t valid_field[] = { 9633 Q_VLD0f, Q_VLD1f, Q_VLD2f, Q_VLD3f 9634 }; 9635 static const soc_field_t num_field[] = { 9636 Q_NUM0f, Q_NUM1f, Q_NUM2f, Q_NUM3f 9637 }; 9638 uint32 profile_index; 9639 uint64 rval64[16], *rval64s[1]; 9640 uint32 rval, bmp; 9641 9642 if (IS_CPU_PORT(unit, port)) { 9643 return BCM_E_PORT; 9644 } 9645 9646 if ((gport == NULL) && (gport_count > 0)) { 9647 return BCM_E_PARAM; 9648 } 9649 9650 if (actual_gport_count == NULL) { 9651 return BCM_E_PARAM; 9652 } 9653 9654 BCM_IF_ERROR_RETURN 9655 (_bcm_td_cosq_localport_resolve(unit, port, &local_port)); 9656 9657 BCM_IF_ERROR_RETURN(_bcm_td_cosq_pfc_class_resolve(sctype, &type, &class)); 9658 9659 port_info = &_bcm_td_cosq_port_info[unit][local_port]; 9660 count = 0; 9661 9662 rval64s[0] = rval64; 9663 BCM_IF_ERROR_RETURN(READ_PORT_LLFC_CFGr(unit, local_port, &rval)); 9664 if (type == _BCM_TD_COSQ_TYPE_UCAST || type == _BCM_TD_COSQ_TYPE_MCAST) { 9665 profile_index = soc_reg_field_get(unit, PORT_LLFC_CFGr, rval, 9666 PROFILE_INDEXf) * 16; 9667 BCM_IF_ERROR_RETURN 9668 (soc_profile_reg_get(unit, _bcm_td_llfc_profile[unit], 9669 profile_index, 16, rval64s)); 9670 if (type == _BCM_TD_COSQ_TYPE_UCAST) { 9671 bmp = soc_reg64_field32_get(unit, PRIO2COS_LLFCr, rval64[class], 9672 UC_COS0_10_BMPf); 9673 for (hw_cosq = 0; hw_cosq < _BCM_TD_NUM_UCAST_QUEUE_GROUP; 9674 hw_cosq++) { 9675 if (!(bmp & (1 << hw_cosq))) { 9676 continue; 9677 } 9678 for (id = 0; id < _BCM_TD_NUM_UCAST_QUEUE_GROUP; id++) { 9679 if (port_info->ucast[id].parent == NULL || 9680 port_info->ucast[id].base != hw_cosq) { 9681 continue; 9682 } 9683 if (gport_count > 0) { 9684 gport[count] = port_info->ucast[id].gport; 9685 } 9686 count++; 9687 break; 9688 } 9689 if (id == _BCM_TD_NUM_UCAST_QUEUE_GROUP) { 9690 if (gport_count > 0) { 9691 gport[count] = hw_cosq; 9692 } 9693 count++; 9694 } 9695 if ((gport_count > 0) && (count == gport_count)) { 9696 break; 9697 } 9698 } 9699 } else { 9700 bmp = soc_reg64_field32_get(unit, PRIO2COS_LLFCr, rval64[class], 9701 MC_COS0_5_BMPf); 9702 for (hw_cosq = 0; hw_cosq < _BCM_TD_NUM_MCAST_QUEUE_GROUP; 9703 hw_cosq++) { 9704 if (!(bmp & (1 << hw_cosq))) { 9705 continue; 9706 } 9707 for (id = 0; id < _BCM_TD_NUM_MCAST_QUEUE_GROUP; id++) { 9708 if (port_info->mcast[id].parent == NULL || 9709 port_info->mcast[id].base != hw_cosq) { 9710 continue; 9711 } 9712 if (gport_count > 0) { 9713 gport[count] = port_info->mcast[id].gport; 9714 } 9715 count++; 9716 break; 9717 } 9718 if (id == _BCM_TD_NUM_MCAST_QUEUE_GROUP) { 9719 if (gport_count > 0) { 9720 gport[count] = hw_cosq; 9721 } 9722 count++; 9723 } 9724 if ((gport_count > 0) && (count == gport_count)) { 9725 break; 9726 } 9727 } 9728 } 9729 } else { 9730 profile_index = soc_reg_field_get(unit, PORT_LLFC_CFGr, rval, 9731 EXT_PER_Q_INDEXf) * 16; 9732 BCM_IF_ERROR_RETURN 9733 (soc_profile_reg_get(unit, _bcm_td_ext_llfc_profile[unit], 9734 profile_index, 16, rval64s)); 9735 for (i = 0; i < sizeof(num_field) / sizeof(num_field[0]); i++) { 9736 if (!soc_reg64_field32_get(unit, PRIO2EXTQ_LLFCr, 9737 rval64[class], valid_field[i])) { 9738 continue; 9739 } 9740 hw_cosq = soc_reg64_field32_get(unit, PRIO2EXTQ_LLFCr, 9741 rval64[class], num_field[i]) - 64; 9742 for (id = 0; id < _BCM_TD_NUM_EXT_UCAST_QUEUE_GROUP; id++) { 9743 if (port_info->ext_ucast[id].parent == NULL || 9744 port_info->ext_ucast[id].base != hw_cosq) { 9745 continue; 9746 } 9747 if (gport_count > 0) { 9748 gport[count] = port_info->ext_ucast[id].gport; 9749 } 9750 count++; 9751 break; 9752 } 9753 if (id == _BCM_TD_NUM_EXT_UCAST_QUEUE_GROUP) { 9754 if (gport_count > 0) { 9755 gport[count] = hw_cosq; 9756 } 9757 count++; 9758 } 9759 if ((gport_count > 0) && (count == gport_count)) { 9760 break; 9761 } 9762 } 9763 } 9764 9765 if (count == 0) { 9766 return BCM_E_NOT_FOUND; 9767 } 9768 *actual_gport_count = count; 9769 return BCM_E_NONE; 9770 } 9771 9772 /* 9773 * Function: 9774 * bcm_td_cosq_pfc_class_mapping_set 9775 * Purpose: 9776 * Set PFC mapping for port. PFC class is mapped to cosq. 9777 * Parameters: 9778 * unit - (IN) unit number 9779 * port - (IN) port number 9780 * array_count - (IN) count of mapping 9781 * mapping_array - (IN) mappings 9782 * Returns: 9783 * BCM_E_XXX 9784 */ 9785 int 9786 bcm_td_cosq_pfc_class_mapping_set(int unit, 9787 bcm_gport_t port, 9788 int array_count, 9789 bcm_cosq_pfc_class_mapping_t *mapping_array) 9790 { 9791 int index, count; 9792 int cosq, type; 9793 int cur_class = 0, pfc_class[_BCM_TD_NUM_PFC_CLASS]; 9794 bcm_gport_t cur_gport = 0; 9795 _bcm_td_cosq_pfc_cos_bmp_t cos_bmp[_BCM_TD_NUM_PFC_CLASS]; 9796 9797 9798 if ((array_count < 0) || (array_count > _BCM_TD_NUM_PFC_CLASS)) { 9799 return BCM_E_PARAM; 9800 } 9801 if (mapping_array == NULL) { 9802 return BCM_E_PARAM; 9803 } 9804 9805 sal_memset(cos_bmp, 0, sizeof(cos_bmp)); 9806 for (count = 0; count < array_count; count++) { 9807 cur_class = mapping_array[count].class_id; 9808 if ((cur_class < 0) || (cur_class >= _BCM_TD_NUM_PFC_CLASS)) { 9809 return BCM_E_PARAM; 9810 } 9811 9812 for (index = 0; index < BCM_COSQ_PFC_GPORT_COUNT; index++) { 9813 cur_gport = mapping_array[count].gport_list[index]; 9814 if (cur_gport == BCM_GPORT_INVALID) { 9815 break; 9816 } 9817 9818 if (BCM_GPORT_IS_SET(cur_gport)) { 9819 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(cur_gport)) { 9820 BCM_IF_ERROR_RETURN( 9821 _bcm_td_cosq_node_get(unit, cur_gport, NULL, NULL, 9822 &cosq, NULL)); 9823 9824 if (cosq > _BCM_TD_NUM_UCAST_QUEUE_GROUP) { 9825 /* extended unicast queue */ 9826 type = _BCM_TD_COSQ_TYPE_EXT_UCAST; 9827 } else { 9828 type = _BCM_TD_COSQ_TYPE_UCAST; 9829 } 9830 } else if (BCM_GPORT_IS_MCAST_QUEUE_GROUP(cur_gport)) { 9831 type = _BCM_TD_COSQ_TYPE_MCAST; 9832 } else { 9833 /* Scheduler and other types of gport are not supported. */ 9834 return BCM_E_PARAM; 9835 } 9836 } else { 9837 if (cur_gport > _BCM_TD_NUM_UCAST_QUEUE_GROUP) { 9838 return BCM_E_PARAM; 9839 } else { 9840 /* gport represents the physical Cos value. */ 9841 type = _BCM_TD_COSQ_TYPE_UCAST; 9842 } 9843 } 9844 BCM_IF_ERROR_RETURN( 9845 _bcm_td_fc_status_map_gport(unit, port, type, cur_gport, 9846 &cos_bmp[cur_class])); 9847 } 9848 } 9849 9850 for (index = 0; index < _BCM_TD_NUM_PFC_CLASS; index++) { 9851 pfc_class[index] = index; 9852 } 9853 BCM_IF_ERROR_RETURN(_bcm_td_port_pfc_profile_set(unit, port, 9854 _BCM_COSQ_OP_SET, _BCM_TD_NUM_PFC_CLASS, pfc_class, cos_bmp)); 9855 9856 return BCM_E_NONE; 9857 } 9858 9859 /* 9860 * Function: 9861 * bcm_td_cosq_pfc_class_mapping_get 9862 * Purpose: 9863 * Get PFC mapping for port. 9864 * Retrieves cosq gport associated to PFC classes. 9865 * Parameters: 9866 * unit - (IN) unit number 9867 * port - (IN) port number 9868 * array_max - (IN) max retrieve count 9869 * mapping_array - (OUT) mappings 9870 * array_count - (OUT) retrieved mapping count 9871 * Returns: 9872 * BCM_E_XXX 9873 */ 9874 int 9875 bcm_td_cosq_pfc_class_mapping_get(int unit, 9876 bcm_gport_t port, 9877 int array_max, 9878 bcm_cosq_pfc_class_mapping_t *mapping_array, 9879 int *array_count) 9880 { 9881 int rv = 0; 9882 int cur_class = 0; 9883 int actual_gport_count, class_count = 0; 9884 bcm_switch_control_t sc[] = { bcmSwitchPFCClass0Queue, 9885 bcmSwitchPFCClass1Queue, 9886 bcmSwitchPFCClass2Queue, 9887 bcmSwitchPFCClass3Queue, 9888 bcmSwitchPFCClass4Queue, 9889 bcmSwitchPFCClass5Queue, 9890 bcmSwitchPFCClass6Queue, 9891 bcmSwitchPFCClass7Queue 9892 }; 9893 9894 if ((mapping_array == NULL) && (array_max > 0)) { 9895 return BCM_E_PARAM; 9896 } 9897 if (array_count == NULL) { 9898 return BCM_E_PARAM; 9899 } 9900 9901 for (cur_class = 0; cur_class < _BCM_TD_NUM_PFC_CLASS; cur_class++) { 9902 actual_gport_count = 0; 9903 if (array_max > 0) { 9904 rv = bcm_td_cosq_port_pfc_get(unit, port, sc[cur_class], 9905 mapping_array[class_count].gport_list, 9906 BCM_COSQ_PFC_GPORT_COUNT, &actual_gport_count); 9907 } else { 9908 rv = bcm_td_cosq_port_pfc_get(unit, port, sc[cur_class], 9909 NULL, -1, &actual_gport_count); 9910 } 9911 if (rv == BCM_E_NONE) { 9912 if (array_max > 0) { 9913 mapping_array[class_count].class_id = cur_class; 9914 if (actual_gport_count < BCM_COSQ_PFC_GPORT_COUNT) { 9915 mapping_array[class_count].gport_list[actual_gport_count] = 9916 BCM_GPORT_INVALID; 9917 } 9918 } 9919 class_count++; 9920 } else if (rv != BCM_E_NOT_FOUND) { 9921 return rv; 9922 } 9923 9924 if ((class_count == array_max) && (array_max > 0)) { 9925 break; 9926 } 9927 } 9928 9929 *array_count = class_count; 9930 if (class_count == 0) { 9931 return BCM_E_NOT_FOUND; 9932 } 9933 9934 return BCM_E_NONE; 9935 } 9936 9937 /* 9938 * Function: 9939 * bcm_td_cosq_gport_attach 9940 * Purpose: 9941 * Attach sched_port to the specified index (cosq) of input_port 9942 * Parameters: 9943 * unit - (IN) unit number 9944 * sched_port - (IN) scheduler GPORT identifier 9945 * input_port - (IN) GPORT to attach to 9946 * cosq - (IN) COS queue to attach to (-1 for first available cosq) 9947 * Returns: 9948 * BCM_E_XXX 9949 */ 9950 int 9951 bcm_td_cosq_gport_attach(int unit, bcm_gport_t sched_gport, 9952 bcm_gport_t input_gport, bcm_cos_queue_t cosq) 9953 { 9954 _bcm_td_cosq_node_t *sched_node, *input_node; 9955 bcm_port_t sched_port, input_port; 9956 int rv; 9957 9958 LOG_INFO(BSL_LS_BCM_COSQ, 9959 (BSL_META_U(unit, 9960 "bcm_td_cosq_gport_attach: unit=%d sched_port=0x%x " 9961 "input_port=0x%x cosq=%d\n"), 9962 unit, sched_gport, input_gport, cosq)); 9963 9964 BCM_IF_ERROR_RETURN 9965 (_bcm_td_cosq_node_get(unit, sched_gport, NULL, &sched_port, NULL, 9966 &sched_node)); 9967 9968 if (sched_node->cosq_attached_to >= 0) { 9969 /* Has already attached */ 9970 return BCM_E_EXISTS; 9971 } 9972 9973 if (BCM_GPORT_IS_SCHEDULER(input_gport)) { 9974 BCM_IF_ERROR_RETURN 9975 (_bcm_td_cosq_node_get(unit, input_gport, NULL, &input_port, NULL, 9976 &input_node)); 9977 } else { 9978 BCM_IF_ERROR_RETURN 9979 (_bcm_td_cosq_localport_resolve(unit, input_gport, &input_port)); 9980 input_node = NULL; 9981 } 9982 9983 if (sched_port != input_port) { 9984 return BCM_E_PORT; 9985 } 9986 9987 if (input_node != NULL) { /* sched_gport is not an S1 scheduler */ 9988 if (input_node->cosq_attached_to < 0) { 9989 /* Only allow to attach to a node that has already attached */ 9990 return BCM_E_PARAM; 9991 } 9992 if (cosq < -1 || cosq >= input_node->numq) { 9993 return BCM_E_PARAM; 9994 } 9995 sched_node->parent = input_node; 9996 sched_node->sibling = input_node->child; 9997 input_node->child = sched_node; 9998 rv = _bcm_td_cosq_node_resolve(unit, input_port, sched_node, cosq); 9999 if (BCM_FAILURE(rv)) { 10000 input_node->child = sched_node->sibling; 10001 return rv; 10002 } 10003 BCM_IF_ERROR_RETURN(_bcm_td_cosq_sched_node_set(unit, sched_port)); 10004 10005 LOG_INFO(BSL_LS_BCM_COSQ, 10006 (BSL_META_U(unit, 10007 " hw_cosq=%d\n"), 10008 sched_node->hw_cosq_attached_to)); 10009 } else { /* sched_gport is an S1 scheduler */ 10010 if (!BCM_GPORT_IS_SCHEDULER(sched_gport)) { 10011 return BCM_E_PORT; 10012 } 10013 10014 if (sched_node->numq > _BCM_TD_S1_SCHEDULER_NUM_INPUT) { 10015 return BCM_E_FAIL; 10016 } 10017 sched_node->cosq_attached_to = 0; 10018 sched_node->hw_cosq_attached_to = 0; 10019 sched_node->level = 1; 10020 } 10021 10022 #if 0 10023 BCM_IF_ERROR_RETURN 10024 (soc_reg_field32_modify(unit, ING_COS_MODEr, input_port, 10025 SELECTf, 0x3)); /* VLAN_COS */ 10026 BCM_IF_ERROR_RETURN 10027 (soc_reg_field32_modify(unit, COS_MODEr, input_port, 10028 SELECTf, 0x3)); /* VLAN_COS */ 10029 #endif 10030 10031 return BCM_E_NONE; 10032 } 10033 10034 /* 10035 * Function: 10036 * bcm_td_cosq_gport_detach 10037 * Purpose: 10038 * Detach sched_port from the specified index (cosq) of input_port 10039 * Parameters: 10040 * unit - (IN) unit number 10041 * sched_port - (IN) scheduler GPORT identifier 10042 * input_port - (IN) GPORT to detach from 10043 * cosq - (IN) COS queue to detach from 10044 * Returns: 10045 * BCM_E_XXX 10046 */ 10047 int 10048 bcm_td_cosq_gport_detach(int unit, bcm_gport_t sched_gport, 10049 bcm_gport_t input_gport, bcm_cos_queue_t cosq) 10050 { 10051 _bcm_td_cosq_node_t *sched_node, *input_node, *prev_node; 10052 bcm_port_t sched_port, input_port; 10053 10054 LOG_INFO(BSL_LS_BCM_COSQ, 10055 (BSL_META_U(unit, 10056 "bcm_td_cosq_gport_detach: unit=%d sched_port=0x%x " 10057 "input_port=0x%x cosq=%d\n"), 10058 unit, sched_gport, input_gport, cosq)); 10059 10060 BCM_IF_ERROR_RETURN 10061 (_bcm_td_cosq_node_get(unit, sched_gport, NULL, &sched_port, NULL, 10062 &sched_node)); 10063 10064 if (sched_node->cosq_attached_to < 0) { 10065 /* Not attached yet */ 10066 return BCM_E_PORT; 10067 } 10068 10069 /* input_gport argument is redundant, check if it is specified */ 10070 if (input_gport != BCM_GPORT_INVALID) { 10071 if (BCM_GPORT_IS_SCHEDULER(input_gport)) { 10072 BCM_IF_ERROR_RETURN 10073 (_bcm_td_cosq_node_get(unit, input_gport, NULL, &input_port, 10074 NULL, &input_node)); 10075 } else { 10076 BCM_IF_ERROR_RETURN 10077 (_bcm_td_cosq_localport_resolve(unit, input_gport, 10078 &input_port)); 10079 input_node = NULL; 10080 } 10081 if (sched_port != input_port) { 10082 return BCM_E_PORT; 10083 } 10084 if (sched_node->parent != input_node) { 10085 return BCM_E_PORT; 10086 } 10087 } 10088 10089 /* cosq argument is redundant, check if it is specified */ 10090 if (cosq != -1) { 10091 if (sched_node->parent == NULL) { 10092 /*schedule node is S1*/ 10093 if (sched_node->cosq_attached_to != 0) { 10094 return BCM_E_PARAM; 10095 } 10096 } else if (sched_node->cosq_attached_to != cosq) { 10097 return BCM_E_PARAM; 10098 } 10099 } 10100 10101 if (sched_node->parent != NULL) { /* sched_node is not an S1 scheduler */ 10102 if (sched_node->parent->child == sched_node) { 10103 sched_node->parent->child = sched_node->sibling; 10104 } else { 10105 prev_node = sched_node->parent->child; 10106 while (prev_node != NULL && prev_node->sibling != sched_node) { 10107 prev_node = prev_node->sibling; 10108 } 10109 if (prev_node == NULL) { 10110 return BCM_E_INTERNAL; 10111 } 10112 prev_node->sibling = sched_node->sibling; 10113 } 10114 sched_node->parent = NULL; 10115 sched_node->sibling = NULL; 10116 } 10117 10118 BCM_IF_ERROR_RETURN(_bcm_td_cosq_node_unresolve(unit, sched_node)); 10119 BCM_IF_ERROR_RETURN(_bcm_td_cosq_sched_node_set(unit, sched_port)); 10120 10121 #if 0 10122 BCM_IF_ERROR_RETURN 10123 (soc_reg_field32_modify(unit, COS_MODEr, input_port, SELECTf, 0x0)); 10124 BCM_IF_ERROR_RETURN 10125 (soc_reg_field32_modify(unit, ING_COS_MODEr, input_port, SELECTf, 0x0)); 10126 #endif 10127 10128 return BCM_E_NONE; 10129 } 10130 10131 /* 10132 * Function: 10133 * bcm_td_cosq_gport_attach_get 10134 * Purpose: 10135 * Get attached status of a scheduler port 10136 * Parameters: 10137 * unit - (IN) unit number 10138 * sched_port - (IN) scheduler GPORT identifier 10139 * input_port - (OUT) GPORT to attach to 10140 * cosq - (OUT) COS queue to attached to 10141 * Returns: 10142 * BCM_E_XXX 10143 * Notes: 10144 */ 10145 int 10146 bcm_td_cosq_gport_attach_get(int unit, bcm_gport_t sched_gport, 10147 bcm_gport_t *input_gport, bcm_cos_queue_t *cosq) 10148 { 10149 _bcm_td_cosq_node_t *sched_node; 10150 bcm_module_t modid, modid_out; 10151 bcm_port_t port, port_out; 10152 10153 if (input_gport == NULL || cosq == NULL) { 10154 return BCM_E_PARAM; 10155 } 10156 10157 BCM_IF_ERROR_RETURN 10158 (_bcm_td_cosq_node_get(unit, sched_gport, &modid, &port, NULL, 10159 &sched_node)); 10160 10161 if (sched_node->cosq_attached_to < 0) { 10162 /* Not attached yet */ 10163 return BCM_E_NOT_FOUND; 10164 } 10165 10166 if (sched_node->parent != NULL) { /* sched_node is not an S1 scheduler */ 10167 *input_gport = sched_node->parent->gport; 10168 } else { /* sched_node is an S1 scheduler */ 10169 BCM_IF_ERROR_RETURN 10170 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET, modid, port, 10171 &modid_out, &port_out)); 10172 BCM_GPORT_MODPORT_SET(*input_gport, modid_out, port_out); 10173 } 10174 *cosq = sched_node->cosq_attached_to; 10175 10176 return BCM_E_NONE; 10177 } 10178 10179 STATIC const soc_reg_t hg_voqfc_msg_sel_reg[8] = { 10180 VOQFC_MSG_PORT_SEL0r, 10181 VOQFC_MSG_PORT_SEL1r, 10182 VOQFC_MSG_PORT_SEL2r, 10183 VOQFC_MSG_PORT_SEL3r, 10184 VOQFC_MSG_PORT_SEL4r, 10185 VOQFC_MSG_PORT_SEL5r, 10186 VOQFC_MSG_PORT_SEL6r, 10187 VOQFC_MSG_PORT_SEL7r 10188 }; 10189 10190 STATIC const soc_reg_t hg_voqfc_group_merge_reg[8] = { 10191 VOQFC_STATE_MERGE_GRP0r, 10192 VOQFC_STATE_MERGE_GRP1r, 10193 VOQFC_STATE_MERGE_GRP2r, 10194 VOQFC_STATE_MERGE_GRP3r, 10195 VOQFC_STATE_MERGE_GRP4r, 10196 VOQFC_STATE_MERGE_GRP5r, 10197 VOQFC_STATE_MERGE_GRP6r, 10198 VOQFC_STATE_MERGE_GRP7r 10199 }; 10200 10201 /* 10202 * Returns index of the port for indexing into MSG_SEL. 10203 */ 10204 STATIC int 10205 _bcm_td_voq_port_index(int unit, bcm_port_t port) 10206 { 10207 soc_info_t *si; 10208 int ii, pipe, mmu_base[2], index = -1; 10209 bcm_port_t phy_port, mmu_port; 10210 10211 si = &SOC_INFO(unit); 10212 10213 phy_port = si->port_l2p_mapping[port]; 10214 10215 if (phy_port < 0) { 10216 return -1; 10217 } 10218 10219 mmu_base[0] = 1; 10220 mmu_base[1] = 34; 10221 10222 for (pipe = 0; pipe < 2; pipe++) { 10223 for (ii = 0; ii < 4; ii++) { 10224 mmu_port = mmu_base[pipe] + ii; 10225 if (si->port_m2p_mapping[mmu_port] == phy_port) { 10226 index = (pipe * 4) + ii; 10227 } 10228 } 10229 } 10230 10231 return index; 10232 } 10233 10234 STATIC int 10235 _bcm_cosq_voq_find_empty_msg_sel_entry(int unit, bcm_port_t port, 10236 bcm_port_t fab_egr_port, 10237 int *msg_sel_index) 10238 { 10239 soc_reg_t merge_grp_reg, msg_sel_reg; 10240 uint32 reg_addr, reg_data; 10241 int ii, pidx = -1; 10242 uint16 used_bmp = 0, profile_bmp; 10243 uint32 fabric_port[16]; 10244 10245 *msg_sel_index = -1; 10246 10247 if ((pidx = _bcm_td_voq_port_index(unit, port)) < 0) { 10248 return BCM_E_UNAVAIL; 10249 } 10250 10251 msg_sel_reg = hg_voqfc_msg_sel_reg[pidx]; 10252 merge_grp_reg = hg_voqfc_group_merge_reg[pidx]; 10253 10254 for (ii = 0; ii < 16; ii++) { 10255 reg_addr = soc_reg_addr(unit, msg_sel_reg, REG_PORT_ANY, ii); 10256 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, reg_addr, ®_data)); 10257 fabric_port[ii] = soc_reg_field_get(unit, msg_sel_reg, reg_data, MSG_PORTf); 10258 } 10259 10260 for (ii = 0; ii < 16; ii++) { 10261 reg_addr = soc_reg_addr(unit, merge_grp_reg, REG_PORT_ANY, ii); 10262 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, reg_addr, ®_data)); 10263 profile_bmp = soc_reg_field_get(unit, merge_grp_reg, 10264 reg_data, MERGE_ST_BMPf); 10265 used_bmp |= profile_bmp; 10266 } 10267 10268 for (ii = 0; ii < 16; ii++) { 10269 /* check already in use */ 10270 if ((used_bmp & (1 << ii)) && (fab_egr_port == fabric_port[ii])) { 10271 *msg_sel_index = ii; 10272 return BCM_E_NONE; 10273 } 10274 } 10275 /* Not found, ok, get an first empty slot */ 10276 for (ii = 0; ii < 16; ii++) { 10277 /* check already in use */ 10278 if ((used_bmp & (1 << ii)) == 0) { 10279 *msg_sel_index = ii; 10280 return BCM_E_NONE; 10281 } 10282 } 10283 10284 return BCM_E_FULL; 10285 } 10286 10287 STATIC int 10288 _bcm_cosq_voq_find_current_msg_sel_entry(int unit, bcm_port_t port, 10289 bcm_port_t fab_egr_port, 10290 int q_group, int *msg_sel_index) 10291 { 10292 soc_reg_t merge_grp_reg, msg_sel_reg; 10293 uint32 reg_addr, reg_data; 10294 int ii, pidx = -1; 10295 uint16 used_bmp = 0, profile_bmp; 10296 uint32 fabric_port[16]; 10297 int from_q_grp, to_q_grp; 10298 10299 *msg_sel_index = -1; 10300 10301 if ((pidx = _bcm_td_voq_port_index(unit, port)) < 0) { 10302 return BCM_E_UNAVAIL; 10303 } 10304 10305 msg_sel_reg = hg_voqfc_msg_sel_reg[pidx]; 10306 merge_grp_reg = hg_voqfc_group_merge_reg[pidx]; 10307 10308 for (ii = 0; ii < 16; ii++) { 10309 reg_addr = soc_reg_addr(unit, msg_sel_reg, REG_PORT_ANY, ii); 10310 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, reg_addr, ®_data)); 10311 fabric_port[ii] = soc_reg_field_get(unit, msg_sel_reg, reg_data, MSG_PORTf); 10312 } 10313 10314 if (q_group < 0) { 10315 from_q_grp = 0; 10316 to_q_grp = 15; 10317 } else { 10318 from_q_grp = to_q_grp = q_group; 10319 } 10320 10321 for (ii = from_q_grp; ii <= to_q_grp; ii++) { 10322 reg_addr = soc_reg_addr(unit, merge_grp_reg, REG_PORT_ANY, ii); 10323 SOC_IF_ERROR_RETURN(soc_reg32_read(unit, reg_addr, ®_data)); 10324 profile_bmp = soc_reg_field_get(unit, merge_grp_reg, reg_data, MERGE_ST_BMPf); 10325 10326 used_bmp |= profile_bmp; 10327 } 10328 10329 /* Not found, ok, get an first empty slot */ 10330 for (ii = 0; ii < 16; ii++) { 10331 if ((used_bmp & (1 << ii)) && (fab_egr_port == fabric_port[ii])) { 10332 *msg_sel_index = ii; 10333 return BCM_E_NONE; 10334 } 10335 } 10336 10337 return BCM_E_NOT_FOUND; 10338 } 10339 10340 STATIC int 10341 _bcm_td_voq_fabric_port_set(int unit, bcm_port_t port, 10342 bcm_port_t fab_egr_port, 10343 int msg_sel_index, int q_grp_idx) 10344 { 10345 soc_reg_t merge_grp_reg, msg_sel; 10346 uint32 reg_data; 10347 int voq_pidx = -1; 10348 uint16 bmp; 10349 10350 if ((voq_pidx = _bcm_td_voq_port_index(unit, port)) < 0) { 10351 return BCM_E_PARAM; 10352 } 10353 10354 msg_sel = hg_voqfc_msg_sel_reg[voq_pidx]; 10355 merge_grp_reg = hg_voqfc_group_merge_reg[voq_pidx]; 10356 10357 reg_data = 0; 10358 soc_reg_field_set(unit, msg_sel, ®_data, MSG_PORTf, fab_egr_port); 10359 BCM_IF_ERROR_RETURN 10360 (soc_reg32_set(unit, msg_sel, REG_PORT_ANY, msg_sel_index, reg_data)); 10361 10362 SOC_IF_ERROR_RETURN 10363 (soc_reg32_get(unit, merge_grp_reg, REG_PORT_ANY, q_grp_idx, 10364 ®_data)); 10365 bmp = soc_reg_field_get(unit, merge_grp_reg, reg_data, MERGE_ST_BMPf); 10366 if ((bmp & (1 << q_grp_idx)) == 0) { 10367 bmp |= (1 << q_grp_idx); 10368 soc_reg_field_set(unit, merge_grp_reg, ®_data, MERGE_ST_BMPf, bmp); 10369 10370 BCM_IF_ERROR_RETURN 10371 (soc_reg32_set(unit, merge_grp_reg, REG_PORT_ANY, q_grp_idx, 10372 reg_data)); 10373 } 10374 10375 return BCM_E_NONE; 10376 } 10377 10378 STATIC int 10379 _bcm_td_voq_fabric_port_unset(int unit, bcm_port_t port, 10380 bcm_port_t fab_egr_port, int q_grp, 10381 uint32 *new_fabric_pbmp) 10382 { 10383 uint32 reg_data; 10384 int voq_pidx = -1; 10385 uint16 profile_bmp, ii, jj; 10386 uint32 fabric_port[16]; 10387 soc_reg_t merge_grp_reg, msg_sel_reg; 10388 10389 if ((voq_pidx = _bcm_td_voq_port_index(unit, port)) < 0) { 10390 return BCM_E_PARAM; 10391 } 10392 10393 msg_sel_reg = hg_voqfc_msg_sel_reg[voq_pidx]; 10394 merge_grp_reg = hg_voqfc_group_merge_reg[voq_pidx]; 10395 10396 for (ii = 0; ii < 16; ii++) { 10397 SOC_IF_ERROR_RETURN 10398 (soc_reg32_get(unit, msg_sel_reg, REG_PORT_ANY, ii, ®_data)); 10399 fabric_port[ii] = soc_reg_field_get(unit, msg_sel_reg, reg_data, MSG_PORTf); 10400 } 10401 10402 SOC_IF_ERROR_RETURN 10403 (soc_reg32_get(unit, merge_grp_reg, REG_PORT_ANY, q_grp, ®_data)); 10404 profile_bmp = soc_reg_field_get(unit, merge_grp_reg, reg_data, 10405 MERGE_ST_BMPf); 10406 10407 for (jj = 0; jj < 16; jj++) { 10408 if ((profile_bmp & (1 << jj)) && (fab_egr_port == fabric_port[jj])) { 10409 profile_bmp &= ~(1 << jj); 10410 10411 soc_reg_field_set(unit, merge_grp_reg, ®_data, 10412 MERGE_ST_BMPf, profile_bmp); 10413 BCM_IF_ERROR_RETURN 10414 (soc_reg32_set(unit, merge_grp_reg, REG_PORT_ANY, q_grp, 10415 reg_data)); 10416 *new_fabric_pbmp = profile_bmp; 10417 break; 10418 } 10419 } 10420 10421 return BCM_E_NONE; 10422 } 10423 10424 STATIC int _bcm_td_cosq_voq_init(int unit, bcm_port_t port) 10425 { 10426 soc_reg_t merge_grp_reg; 10427 uint32 reg_data = 0; 10428 int pidx = -1, ii; 10429 10430 if ((pidx = _bcm_td_voq_port_index(unit, port)) < 0) { 10431 return BCM_E_NONE; 10432 } 10433 10434 merge_grp_reg = hg_voqfc_group_merge_reg[pidx]; 10435 10436 /* 10437 * clear out VOQFC_STATE_MERGE_GRPx registers. 10438 */ 10439 for (ii = 0; ii < 16; ii++) { 10440 soc_reg_field_set(unit, merge_grp_reg, ®_data, MERGE_ST_BMPf, 0); 10441 BCM_IF_ERROR_RETURN 10442 (soc_reg32_set(unit, merge_grp_reg, REG_PORT_ANY, ii, reg_data)); 10443 } 10444 10445 return BCM_E_NONE; 10446 } 10447 10448 STATIC int 10449 _bcm_td_create_default_profile(int unit, bcm_port_t gport, int numq, 10450 _bcm_td_voq_profile_t *profile) 10451 { 10452 int ii; 10453 10454 if ((numq <= 0) || (!profile)) { 10455 return BCM_E_PARAM; 10456 } 10457 10458 profile->hw_index = -1; 10459 profile->id = -1; 10460 10461 for (ii = 0; ii < 16; ii++) { 10462 profile->int_prio2q[ii] = 10463 _BCM_TD_VOQ_GPORT_QUEUE_ID(unit, gport, (ii*numq/16)); 10464 } 10465 return BCM_E_NONE; 10466 } 10467 10468 STATIC int 10469 _bcm_td_add_voq_profile(int unit, _bcm_td_cosq_node_t *node) 10470 { 10471 uint32 new_index; 10472 voq_cos_map_entry_t voq_cos_map_entries[16]; 10473 void *entries[1]; 10474 int ii; 10475 _bcm_td_voq_profile_t *profile = &node->voq_profile; 10476 10477 sal_memset(voq_cos_map_entries, 0, sizeof(voq_cos_map_entries)); 10478 10479 for (ii = 0; ii < 16; ii++) { 10480 soc_mem_field32_set(unit, VOQ_COS_MAPm, 10481 &voq_cos_map_entries[ii], VOQ_COSf, profile->int_prio2q[ii]); 10482 } 10483 10484 entries[0] = &voq_cos_map_entries; 10485 BCM_IF_ERROR_RETURN 10486 (soc_profile_mem_add(unit, _bcm_td_voq_cos_map_profile[unit], 10487 entries, 16, &new_index)); 10488 10489 profile->hw_index = new_index; 10490 profile->id = new_index/16; 10491 10492 return BCM_E_NONE; 10493 } 10494 10495 10496 /* Map internal priority to voq cos */ 10497 STATIC int 10498 _bcm_td_voq_gport_mapping_set(int unit, bcm_port_t gport, int int_prio, 10499 bcm_cos_t cos) 10500 { 10501 _bcm_td_voq_profile_t *profile; 10502 _bcm_td_cosq_node_t *node; 10503 int qid, id, prev_profile_id = -1, profile_id, modid, rv; 10504 bcm_port_t local_port, port, dest_port; 10505 10506 BCM_IF_ERROR_RETURN 10507 (_bcm_td_cosq_node_get(unit, gport, NULL, &local_port, &id, &node)); 10508 10509 profile = &node->voq_profile; 10510 10511 qid = _BCM_TD_VOQ_GPORT_QUEUE_ID(unit, gport, cos); 10512 if (qid == profile->int_prio2q[int_prio]) { 10513 return BCM_E_NONE; 10514 } 10515 10516 profile->int_prio2q[int_prio] = qid; 10517 10518 if (profile->id < 0) { 10519 return BCM_E_NONE; 10520 } 10521 10522 prev_profile_id = profile->id; 10523 10524 /* 10525 * Update modport_sw table for all the ingress ports that use this 10526 * voq group to use new profile. 10527 */ 10528 PBMP_PORT_ITER(unit, port) { 10529 for (modid = 0; modid <= SOC_MODID_MAX(unit); modid++) { 10530 rv = bcm_esw_stk_port_modport_get(unit, port, 10531 modid, &dest_port); 10532 10533 if ((!BCM_SUCCESS(rv)) || (dest_port != local_port)) { 10534 continue; 10535 } 10536 10537 rv = bcm_stk_modport_voq_cosq_profile_get(unit, port, 10538 modid, &profile_id); 10539 if ((!BCM_SUCCESS(rv)) || (prev_profile_id != profile_id)) { 10540 continue; 10541 } 10542 10543 /* 10544 * Add VOQ profile to HW. and delete the previos VOQ profile 10545 */ 10546 BCM_IF_ERROR_RETURN(_bcm_td_add_voq_profile(unit, node)); 10547 10548 BCM_IF_ERROR_RETURN 10549 (soc_profile_mem_delete(unit, _bcm_td_voq_cos_map_profile[unit], 10550 prev_profile_id * 16)); 10551 10552 BCM_IF_ERROR_RETURN 10553 (bcm_stk_modport_voq_cosq_profile_set(unit, port, 10554 modid, profile->id)); 10555 } 10556 } 10557 10558 return BCM_E_NONE; 10559 } 10560 10561 /* 10562 * Function: 10563 * bcm_td_cosq_gport_modid_attach 10564 * Purpose: 10565 * Get attached status of a scheduler port 10566 * Parameters: 10567 * unit - (IN) unit number 10568 * sched_port - (IN) scheduler GPORT identifier 10569 * input_port - (OUT) GPORT to attach to 10570 * cosq - (OUT) COS queue to attached to 10571 * Returns: 10572 * BCM_E_XXX 10573 * Notes: 10574 */ 10575 int 10576 bcm_td_cosq_gport_destmod_attach(int unit, bcm_gport_t gport, 10577 bcm_port_t ing_port, 10578 bcm_module_t dest_modid, 10579 int fabric_egress_port) 10580 { 10581 int q_grp; 10582 bcm_port_t local_port; 10583 int msg_sel_index, cur_profile_id = -1; 10584 _bcm_td_cosq_node_t *node; 10585 _bcm_td_voq_profile_t *profile; 10586 10587 BCM_IF_ERROR_RETURN 10588 (bcm_stk_modport_voq_cosq_profile_get(unit, ing_port, 10589 dest_modid, &cur_profile_id)); 10590 if (cur_profile_id >= 0) { 10591 return BCM_E_BUSY; 10592 } 10593 10594 if (!_BCM_TD_IS_VOQ_GPORT(unit, gport)) { 10595 return BCM_E_PARAM; 10596 } 10597 10598 BCM_IF_ERROR_RETURN 10599 (_bcm_td_cosq_node_get(unit, gport, NULL, &local_port, &q_grp, &node)); 10600 if (node == NULL) { 10601 return BCM_E_PARAM; 10602 } 10603 10604 /* 10605 * find an empty index to read VOQFC[port] state. 10606 */ 10607 if (_bcm_cosq_voq_find_empty_msg_sel_entry(unit, local_port, 10608 fabric_egress_port, &msg_sel_index) < 0) { 10609 LOG_ERROR(BSL_LS_BCM_COSQ, 10610 (BSL_META_U(unit, 10611 "Error: unit %d port %d MSG_SEL enteries full \n"), 10612 unit, local_port)); 10613 return BCM_E_FULL; 10614 } 10615 10616 q_grp = q_grp - _BCM_TD_NUM_UCAST_QUEUE_GROUP; 10617 SOC_IF_ERROR_RETURN 10618 (_bcm_td_voq_fabric_port_set(unit, local_port, 10619 fabric_egress_port, msg_sel_index, q_grp)); 10620 10621 BCM_IF_ERROR_RETURN(_bcm_td_add_voq_profile(unit, node)); 10622 10623 profile = &node->voq_profile; 10624 10625 /* update modport table to new profile */ 10626 BCM_IF_ERROR_RETURN 10627 (bcm_stk_modport_voq_cosq_profile_set(unit, ing_port, 10628 dest_modid, profile->id)); 10629 return BCM_E_NONE; 10630 } 10631 10632 /* 10633 * Function: 10634 * bcm_td_cosq_gport_modid_detach 10635 * Purpose: 10636 * Get attached status of a scheduler port 10637 * Parameters: 10638 * unit - (IN) unit number 10639 * sched_port - (IN) scheduler GPORT identifier 10640 * input_port - (OUT) GPORT to attach to 10641 * cosq - (OUT) COS queue to attached to 10642 * Returns: 10643 * BCM_E_XXX 10644 * Notes: 10645 */ 10646 int 10647 bcm_td_cosq_gport_destmod_detach(int unit, bcm_gport_t gport, 10648 bcm_port_t ing_port, 10649 bcm_module_t dest_modid, 10650 int fabric_egress_port) 10651 { 10652 int qid, q_grp, id, rv; 10653 _bcm_td_voq_profile_t *profile; 10654 bcm_port_t local_port, port, m_dest_port; 10655 int msg_sel_index, cur_profile_id = -1, use_cnt, profile_id; 10656 uint32 new_fab_pbmp; 10657 _bcm_td_cosq_node_t *node; 10658 10659 if (!_BCM_TD_IS_VOQ_GPORT(unit, gport)) { 10660 return BCM_E_PARAM; 10661 } 10662 10663 local_port = BCM_GPORT_UCAST_QUEUE_GROUP_SYSPORTID_GET(gport); 10664 if (!_BCM_TD_IS_PORT_DMVOQ_CAPABLE(unit, local_port)) { 10665 LOG_ERROR(BSL_LS_BCM_COSQ, 10666 (BSL_META_U(unit, 10667 "Error: unit %d port %d is not a DestMod flow-control capable \n"), 10668 unit, local_port)); 10669 return BCM_E_PARAM; 10670 } 10671 10672 BCM_IF_ERROR_RETURN 10673 (bcm_stk_modport_voq_cosq_profile_get(unit, ing_port, 10674 dest_modid, &cur_profile_id)); 10675 10676 /* 10677 * check if port really has a VOQ profile attached to it. 10678 */ 10679 if (cur_profile_id < 0) { 10680 return BCM_E_NONE; 10681 } 10682 10683 /* 10684 * Get the cosmap profile and add to HW. 10685 */ 10686 BCM_IF_ERROR_RETURN 10687 (_bcm_td_cosq_node_get(unit, gport, NULL, &local_port, &id, &node)); 10688 10689 profile = &node->voq_profile; 10690 10691 /* 10692 * validate that the profile we are trying to detach is really 10693 * the one attached to this port. 10694 */ 10695 if (cur_profile_id != profile->id) { 10696 return BCM_E_PARAM; 10697 } 10698 10699 qid = _BCM_TD_VOQ_GPORT_QUEUE_ID(unit, gport, 0); 10700 q_grp = (qid - _BCM_TD_VOQ_QID_MIN_ID) % 16; 10701 10702 /* 10703 * Disconnect VOQ profile for this ingress port. 10704 */ 10705 BCM_IF_ERROR_RETURN 10706 (bcm_stk_modport_voq_cosq_profile_set(unit, ing_port, dest_modid, -1)); 10707 10708 10709 BCM_IF_ERROR_RETURN 10710 (soc_profile_mem_delete(unit, _bcm_td_voq_cos_map_profile[unit], 10711 profile->hw_index)); 10712 10713 /* 10714 * get the number of ports still using this profile. if none clear 10715 * out msg_sel register. 10716 */ 10717 use_cnt = 0; 10718 PBMP_PORT_ITER(unit, port) { 10719 rv = bcm_esw_stk_port_modport_get(unit, port, 10720 dest_modid, &m_dest_port); 10721 10722 if ((BCM_FAILURE(rv)) || (m_dest_port != local_port)) { 10723 continue; 10724 } 10725 10726 rv = bcm_stk_modport_voq_cosq_profile_get(unit, port, 10727 dest_modid, &profile_id); 10728 10729 if ((BCM_FAILURE(rv)) || (profile->id != profile_id)) { 10730 continue; 10731 } 10732 use_cnt++; 10733 } 10734 10735 if (use_cnt) { 10736 return BCM_E_NONE; 10737 } 10738 10739 SOC_IF_ERROR_RETURN 10740 (_bcm_cosq_voq_find_current_msg_sel_entry(unit, local_port, 10741 fabric_egress_port, q_grp, &msg_sel_index)); 10742 10743 if (msg_sel_index < 0) { 10744 return BCM_E_NOT_FOUND; 10745 } 10746 10747 SOC_IF_ERROR_RETURN 10748 (_bcm_td_voq_fabric_port_unset(unit, local_port, 10749 fabric_egress_port, q_grp, &new_fab_pbmp)); 10750 profile->id = -1; 10751 profile->hw_index = -1; 10752 10753 return BCM_E_NONE; 10754 } 10755 10756 /* 10757 * Function: 10758 * bcm_td_cosq_cpu_cosq_enable_set 10759 * Purpose: 10760 * To enable/disable Rx of packets on the specified CPU cosq. 10761 * Parameters: 10762 * unit - (IN) Unit number. 10763 * cosq - (IN) CPU Cosq ID 10764 * enable - (IN) Enable/Disable 10765 * Returns: 10766 * BCM_E_xxx 10767 */ 10768 int 10769 bcm_td_cosq_cpu_cosq_enable_set( 10770 int unit, 10771 bcm_cos_queue_t cosq, 10772 int enable) 10773 { 10774 uint32 rval, rval1; 10775 int enable_status; 10776 soc_info_t *si; 10777 _bcm_td_cosq_cpu_cosq_config_t *cpu_cosq; 10778 10779 si = &SOC_INFO(unit); 10780 10781 if ((cosq < 0) || (cosq >= si->num_cpu_cosq)) { 10782 return BCM_E_PARAM; 10783 } 10784 10785 cpu_cosq = _bcm_td_cosq_cpu_cosq_config[unit][cosq]; 10786 10787 if (!cpu_cosq) { 10788 return BCM_E_INTERNAL; 10789 } 10790 if (enable) { 10791 enable = 1; 10792 } 10793 BCM_IF_ERROR_RETURN(bcm_td_cosq_cpu_cosq_enable_get(unit, cosq, 10794 &enable_status)); 10795 if (enable == enable_status) { 10796 return BCM_E_NONE; 10797 } 10798 10799 BCM_IF_ERROR_RETURN 10800 (READ_OP_QUEUE_CONFIG_CELLr(unit, 0, cosq, &rval)); 10801 BCM_IF_ERROR_RETURN 10802 (READ_OP_QUEUE_CONFIG1_CELLr(unit, 0, cosq, &rval1)); 10803 10804 if (enable) { 10805 soc_reg_field_set(unit, OP_QUEUE_CONFIG_CELLr, &rval, 10806 Q_SHARED_LIMIT_CELLf, cpu_cosq->q_shared_limit); 10807 soc_reg_field_set(unit, OP_QUEUE_CONFIG_CELLr, &rval, 10808 Q_MIN_CELLf, cpu_cosq->q_min_limit); 10809 } else { 10810 cpu_cosq->q_shared_limit = soc_reg_field_get(unit, 10811 OP_QUEUE_CONFIG_CELLr, 10812 rval, 10813 Q_SHARED_LIMIT_CELLf); 10814 cpu_cosq->q_min_limit = soc_reg_field_get(unit, 10815 OP_QUEUE_CONFIG_CELLr, 10816 rval, 10817 Q_MIN_CELLf); 10818 cpu_cosq->q_limit_dynamic = soc_reg_field_get(unit, 10819 OP_QUEUE_CONFIG1_CELLr, 10820 rval1, 10821 Q_LIMIT_DYNAMIC_CELLf); 10822 cpu_cosq->q_limit_enable = soc_reg_field_get(unit, 10823 OP_QUEUE_CONFIG1_CELLr, 10824 rval1, 10825 Q_LIMIT_ENABLE_CELLf); 10826 } 10827 10828 cpu_cosq->enable = enable; 10829 soc_reg_field_set(unit, OP_QUEUE_CONFIG1_CELLr, &rval1, 10830 Q_LIMIT_DYNAMIC_CELLf, 10831 enable ? cpu_cosq->q_limit_dynamic : 0); 10832 soc_reg_field_set(unit, OP_QUEUE_CONFIG1_CELLr, &rval1, 10833 Q_LIMIT_ENABLE_CELLf, 10834 enable ? cpu_cosq->q_limit_enable : 1); 10835 BCM_IF_ERROR_RETURN 10836 (WRITE_OP_QUEUE_CONFIG1_CELLr(unit, 0, cosq, rval1)); 10837 BCM_IF_ERROR_RETURN 10838 (WRITE_OP_QUEUE_CONFIG_CELLr(unit, 0, cosq, enable ? rval : 0)); 10839 10840 return BCM_E_NONE; 10841 } 10842 10843 /* 10844 * Function: 10845 * bcm_td_cosq_cpu_cosq_enable_get 10846 * Purpose: 10847 * To get enable/disable status on Rx of packets on the specified CPU cosq. 10848 * Parameters: 10849 * unit - (IN) Unit number. 10850 * cosq - (IN) CPU Cosq ID 10851 * enable - (OUT) Enable/Disable 10852 * Returns: 10853 * BCM_E_xxx 10854 */ 10855 int 10856 bcm_td_cosq_cpu_cosq_enable_get( 10857 int unit, 10858 bcm_cos_queue_t cosq, 10859 int *enable) 10860 { 10861 _bcm_td_cosq_cpu_cosq_config_t *cpu_cosq; 10862 soc_info_t *si; 10863 uint32 rval, rval1; 10864 uint32 min_limit, shared_limit, limit_enable, dynamic_enable; 10865 int hw_enable; 10866 10867 si = &SOC_INFO(unit); 10868 10869 if ((cosq < 0) || (cosq >= si->num_cpu_cosq)) { 10870 return BCM_E_PARAM; 10871 } 10872 10873 cpu_cosq = _bcm_td_cosq_cpu_cosq_config[unit][cosq]; 10874 if (!cpu_cosq) { 10875 return BCM_E_INTERNAL; 10876 } 10877 10878 hw_enable = 1; 10879 /* Sync up software record with hardware status. */ 10880 BCM_IF_ERROR_RETURN 10881 (READ_OP_QUEUE_CONFIG_CELLr(unit, 0, cosq, &rval)); 10882 BCM_IF_ERROR_RETURN 10883 (READ_OP_QUEUE_CONFIG1_CELLr(unit, 0, cosq, &rval1)); 10884 min_limit = soc_reg_field_get(unit, OP_QUEUE_CONFIG_CELLr, 10885 rval, Q_MIN_CELLf); 10886 shared_limit = soc_reg_field_get(unit, OP_QUEUE_CONFIG_CELLr, 10887 rval, Q_SHARED_LIMIT_CELLf); 10888 limit_enable = soc_reg_field_get(unit, OP_QUEUE_CONFIG1_CELLr, 10889 rval1, Q_LIMIT_ENABLE_CELLf); 10890 dynamic_enable = soc_reg_field_get(unit, OP_QUEUE_CONFIG1_CELLr, 10891 rval1, Q_LIMIT_DYNAMIC_CELLf); 10892 if (limit_enable && (dynamic_enable == 0) && 10893 (min_limit == 0) && (shared_limit == 0)) { 10894 hw_enable = 0; 10895 } 10896 cpu_cosq->enable = hw_enable; 10897 10898 *enable = cpu_cosq->enable; 10899 return BCM_E_NONE; 10900 } 10901 10902 10903 #ifndef BCM_SW_STATE_DUMP_DISABLE 10904 /* 10905 * Function: 10906 * bcm_td_cosq_sw_dump 10907 * Purpose: 10908 * Displays COS Queue information maintained by software. 10909 * Parameters: 10910 * unit - Device unit number 10911 * Returns: 10912 * None 10913 */ 10914 void 10915 bcm_td_cosq_sw_dump(int unit) 10916 { 10917 bcm_port_t port; 10918 10919 LOG_CLI((BSL_META_U(unit, 10920 "\nSW Information COSQ - Unit %d\n"), unit)); 10921 10922 PBMP_ALL_ITER(unit, port) { 10923 if (IS_CPU_PORT(unit, port)) { 10924 continue; 10925 } 10926 (void)_bcm_td_cosq_port_info_dump(unit, port); 10927 } 10928 10929 return; 10930 } 10931 #endif /* BCM_SW_STATE_DUMP_DISABLE */ 10932 10933 /* 10934 * Function: 10935 * _bcm_td_port_enqueue_set 10936 * Purpose: 10937 * Enable or Disable the enqueing the packets to the port 10938 * Parameters: 10939 * unit - (IN) unit number 10940 * gport - (IN) gport of the port 10941 * enable - (IN) TRUE to enable 10942 * FALSE to disable 10943 * Returns: 10944 * BCM_E_XXX 10945 */ 10946 10947 int 10948 _bcm_td_port_enqueue_set(int unit, bcm_port_t gport, 10949 int enable) 10950 { 10951 uint64 rval64 ,rval64_tmp ; 10952 int mmu_port, phy_port; 10953 int i; 10954 int rv = BCM_E_NONE; 10955 bcm_port_t local_port; 10956 soc_info_t *si; 10957 soc_reg_t reg_tmp; 10958 soc_reg_t reg[2][2] = { 10959 { 10960 OUTPUT_PORT_RX_ENABLE0_64r, 10961 OUTPUT_PORT_RX_ENABLE1_64r, 10962 }, 10963 { 10964 INPUT_PORT_RX_ENABLE0_64r, 10965 INPUT_PORT_RX_ENABLE1_64r, 10966 } 10967 }; 10968 10969 COMPILER_64_ZERO(rval64); 10970 COMPILER_64_ZERO(rval64_tmp); 10971 10972 10973 BCM_IF_ERROR_RETURN 10974 (_bcm_td_cosq_localport_resolve(unit, gport, &local_port)); 10975 10976 si = &SOC_INFO(unit); 10977 10978 phy_port = si->port_l2p_mapping[local_port]; 10979 mmu_port = si->port_p2m_mapping[phy_port]; 10980 10981 for (i = 0; i < 2; i++) { 10982 10983 if (SOC_PBMP_MEMBER(si->xpipe_pbm, local_port)) { /* X pipe */ 10984 reg_tmp = reg[i][0]; 10985 } else { /* Y pipe */ 10986 reg_tmp = reg[i][1]; 10987 } 10988 SOC_IF_ERROR_RETURN(soc_reg_get(unit, reg_tmp, REG_PORT_ANY, 0, &rval64)); 10989 10990 mmu_port &= 0x3f; 10991 10992 /* OUTPUT_PORT_RX and INPUT_PORT_RX is organised as follows: 10993 port 0 to port 32 in RX_ENABLE0 and port 33 to 63 in RX_ENABLE1 10994 the following logic is to set 0-32 bits for port 33 to 63 in RX_ENABLE1 */ 10995 10996 if (mmu_port > 32) { 10997 mmu_port = mmu_port - 33; 10998 } 10999 11000 if (mmu_port < 32) { 11001 COMPILER_64_SET(rval64_tmp, 0, 1 << mmu_port); 11002 } else { 11003 COMPILER_64_SET(rval64_tmp, 1 << (mmu_port - 32), 0); 11004 } 11005 11006 if (!enable) { 11007 COMPILER_64_NOT(rval64_tmp); 11008 COMPILER_64_AND(rval64, rval64_tmp); 11009 } else { 11010 COMPILER_64_OR(rval64, rval64_tmp); 11011 } 11012 SOC_IF_ERROR_RETURN(soc_reg_set(unit, reg_tmp, REG_PORT_ANY, 0, rval64)); 11013 } 11014 return rv; 11015 } 11016 11017 /* 11018 * Function: 11019 * _bcm_td_port_enqueue_get 11020 * Purpose: 11021 * Getting the enqueing state of the port 11022 * Parameters: 11023 * unit - (IN) unit number 11024 * gport - (IN) gport of the port 11025 * enable - (OUT) TRUE if enable 11026 * FALSE if disable 11027 * Returns: 11028 * BCM_E_XXX 11029 */ 11030 11031 11032 int 11033 _bcm_td_port_enqueue_get(int unit, bcm_port_t gport, 11034 int *enable) 11035 { 11036 uint64 rval64 ; 11037 int mmu_port, phy_port; 11038 int rv = BCM_E_NONE; 11039 bcm_port_t local_port; 11040 soc_info_t *si; 11041 soc_reg_t reg; 11042 11043 COMPILER_64_ZERO(rval64); 11044 11045 BCM_IF_ERROR_RETURN 11046 (_bcm_td_cosq_localport_resolve(unit, gport, &local_port)); 11047 11048 si = &SOC_INFO(unit); 11049 11050 phy_port = si->port_l2p_mapping[local_port]; 11051 mmu_port = si->port_p2m_mapping[phy_port]; 11052 11053 11054 if (SOC_PBMP_MEMBER(si->xpipe_pbm, local_port)) { /* X pipe */ 11055 reg = OUTPUT_PORT_RX_ENABLE0_64r; 11056 } else { /* Y pipe */ 11057 reg = OUTPUT_PORT_RX_ENABLE1_64r; 11058 } 11059 SOC_IF_ERROR_RETURN(soc_reg_get(unit, reg, REG_PORT_ANY, 0, &rval64)); 11060 11061 mmu_port &= 0x3f; 11062 11063 if (mmu_port > 32) { 11064 mmu_port = mmu_port - 33; 11065 } 11066 if (COMPILER_64_BITTEST(rval64 , mmu_port)) { 11067 *enable = TRUE; 11068 } else { 11069 *enable = FALSE; 11070 } 11071 return rv; 11072 } 11073 11074 /* 11075 * Function: _bcm_td_wred_war_ports_select 11076 * 11077 * Purpose: Selects one extended queue port and one 11078 * regular port from each (X/Y)pipeline. 11079 */ 11080 STATIC int 11081 _bcm_td_wred_war_ports_select(int unit) 11082 { 11083 11084 soc_info_t *si; 11085 soc_port_t local_port; 11086 soc_port_t rcpu_port = 0xff; /* Invalid port number */ 11087 int local_port_mode; 11088 _wred_war_ctrl_t *w; 11089 int valid_port = 0; 11090 mac_driver_t *mac = NULL; 11091 11092 mac = &soc_mac_x; 11093 w = &war; 11094 11095 w->port[0] = w->port[1] = w->port[2] = w->port[3] = -1; 11096 11097 si = &SOC_INFO(unit); 11098 11099 if (SOC_IS_RCPU_UNIT(unit)) { 11100 rcpu_port = RCPU_PORT(unit); 11101 } 11102 11103 PBMP_ALL_ITER(unit, local_port) { 11104 valid_port = PORT_IS_VALID(unit, local_port); 11105 if (!valid_port || (rcpu_port == local_port)) { 11106 continue; 11107 } 11108 11109 SOC_IF_ERROR_RETURN 11110 (MAC_ENCAP_GET(mac, unit, local_port, &local_port_mode)); 11111 11112 if (SOC_PBMP_MEMBER(si->xpipe_pbm, local_port)) { /* X pipe */ 11113 if ((si->port_num_ext_cosq[local_port] == 0) && (w->port[0] == -1)) { 11114 w->port[0] = local_port; /* regular port */ 11115 w->port_mode[0] = local_port_mode; 11116 } else if ((si->port_num_ext_cosq[local_port] != 0) && 11117 (w->port[1] == -1)) { /* extended queue port */ 11118 w->port[1] = local_port; 11119 w->port_mode[1] = local_port_mode; 11120 } else { 11121 continue; 11122 } 11123 } else { /* Y pipe */ 11124 if ((si->port_num_ext_cosq[local_port] == 0) && (w->port[2] == -1)) { 11125 w->port[2] = local_port; /* regular port */ 11126 w->port_mode[2] = local_port_mode; 11127 } else if ((si->port_num_ext_cosq[local_port] != 0) && 11128 (w->port[3] == -1)) { /* extended queue port */ 11129 w->port[3] = local_port; 11130 w->port_mode[3] = local_port_mode; 11131 } else { 11132 continue; 11133 } 11134 } 11135 if ((w->port[0] != -1) && (w->port[1] != -1) && 11136 (w->port[2] != -1) && (w->port[3] != -1)) { 11137 break; 11138 } 11139 } 11140 11141 return SOC_E_NONE; 11142 } 11143 11144 /* 11145 * Function: _bcm_td_wred_war_configure 11146 * 11147 * Purpose: configures wred workaround on ports and switch. 11148 * 11149 * Description : This function function does below things: 11150 * -Stops live traffic by configuring EPC_LINK_BMAP. 11151 * -Converts higig ports into xe ports and removes higig 11152 * configuration that was on the ports. 11153 * -Configures MAC loopback mode on four ports. 11154 * -Configures MAC CRC mode to 1 to generate CRC packetsi. 11155 * -Enables CRC checks on the switch and configures ING_PRI_CNG 11156 * map table to mark ingress packets with red color. 11157 */ 11158 STATIC int 11159 _bcm_td_wred_war_configure(int unit) 11160 { 11161 int i; 11162 uint32 rval; 11163 uint64 tx_ctrl; 11164 pbmp_t pbm; 11165 uint32 stg_entry[SOC_MAX_MEM_WORDS]; 11166 mac_driver_t *mac = NULL; 11167 _wred_war_ctrl_t *w; 11168 port_tab_entry_t p_entry; 11169 epc_link_bmap_entry_t epc_entry; 11170 uint32 pri_map[SOC_MAX_MEM_FIELD_WORDS]; 11171 11172 sal_memset(pri_map, 0, sizeof(pri_map)); 11173 11174 11175 mac = &soc_mac_x; 11176 w = &war; 11177 11178 SOC_PBMP_CLEAR(pbm); 11179 /* Reads default link status.*/ 11180 SOC_IF_ERROR_RETURN(READ_EPC_LINK_BMAPm(unit, MEM_BLOCK_ALL, 11181 0, &w->epc_entry)); 11182 11183 /* Reads default STG mode on switch.*/ 11184 SOC_IF_ERROR_RETURN(soc_mem_read(unit, STG_TABm, MEM_BLOCK_ANY, 1, w->stg_entry)); 11185 11186 sal_memset(&epc_entry, 0, sizeof(epc_entry)); 11187 sal_memset(&stg_entry, 0, sizeof(stg_entry)); 11188 11189 /* Removes all ports from EPC_LINK_BMAP table. */ 11190 if (SOC_IS_RCPU_UNIT(unit)) { 11191 SOC_PBMP_PORT_ADD(pbm, RCPU_PORT(unit)); 11192 } 11193 soc_mem_pbmp_field_set(unit, EPC_LINK_BMAPm, &epc_entry, PORT_BITMAPf, &pbm); 11194 SOC_IF_ERROR_RETURN(WRITE_EPC_LINK_BMAPm(unit, MEM_BLOCK_ALL, 11195 0, &epc_entry)); 11196 11197 for (i = 0; i < SOC_WRED_WR_MAX_NUM_PORTS; i++) { 11198 if (w->port[i] == -1) { 11199 continue; 11200 } 11201 11202 /*Get current settings of each port*/ 11203 BCM_IF_ERROR_RETURN(bcm_esw_port_enable_get(unit, w->port[i], &w->enable[i])); 11204 BCM_IF_ERROR_RETURN(bcm_esw_port_speed_get(unit, w->port[i], &w->speed[i])); 11205 BCM_IF_ERROR_RETURN(bcm_esw_port_duplex_get(unit, w->port[i], &w->duplex[i])); 11206 BCM_IF_ERROR_RETURN(bcm_esw_port_advert_get(unit, w->port[i], &w->advert[i])); 11207 BCM_IF_ERROR_RETURN(bcm_esw_port_autoneg_get(unit, w->port[i], &w->autoneg[i])); 11208 11209 /* Configures IEEE mode on all non IEEE ports.*/ 11210 if ((w->port_mode[i] != SOC_ENCAP_IEEE) && SOC_IS_TRIDENT(unit)) { 11211 SOC_IF_ERROR_RETURN(MAC_ENCAP_SET(mac, unit, w->port[i], 11212 SOC_ENCAP_IEEE)); 11213 SOC_IF_ERROR_RETURN(soc_mem_field32_modify(unit, EGR_PORTm, 11214 w->port[i], HIGIG2f, 0)); 11215 SOC_IF_ERROR_RETURN(soc_reg_field32_modify(unit, XLPORT_CONFIGr, 11216 w->port[i], HIGIG2_MODEf, 0)); 11217 SOC_IF_ERROR_RETURN(soc_mem_field32_modify(unit, EGR_ING_PORTm, 11218 w->port[i], HIGIG2f, 0)); 11219 } 11220 11221 BCM_IF_ERROR_RETURN(bcm_esw_port_enable_set(unit, w->port[i], w->enable[i])); 11222 /* Configures MAC loop back on port.*/ 11223 SOC_IF_ERROR_RETURN(bcm_esw_port_loopback_set(unit, w->port[i], BCM_PORT_LOOPBACK_MAC)); 11224 11225 /* Configures XMAC_TX_CTRL register to send FCS packets. */ 11226 SOC_IF_ERROR_RETURN(READ_XMAC_TX_CTRLr(unit, w->port[i], &tx_ctrl)); 11227 w->port_crc_mode[i] = soc_reg64_field32_get(unit, XMAC_TX_CTRLr, 11228 tx_ctrl, CRC_MODEf); 11229 soc_reg64_field32_set(unit, XMAC_TX_CTRLr, &tx_ctrl, CRC_MODEf, 1); 11230 SOC_IF_ERROR_RETURN(WRITE_XMAC_TX_CTRLr(unit, w->port[i], tx_ctrl)); 11231 11232 /* Set PORT_BRIDGE bit on port.*/ 11233 SOC_IF_ERROR_RETURN(soc_mem_read(unit, PORT_TABm, MEM_BLOCK_ANY, 11234 w->port[i], &w->port_entry[i])); 11235 sal_memcpy(&p_entry, &w->port_entry[i], sizeof(p_entry)); 11236 soc_mem_field32_set(unit, PORT_TABm, &p_entry, PORT_BRIDGEf, 1); 11237 SOC_IF_ERROR_RETURN(soc_mem_write(unit, PORT_TABm, MEM_BLOCK_ALL, 11238 w->port[i], &p_entry)); 11239 11240 SOC_PBMP_PORT_ADD(pbm, w->port[i]); 11241 11242 stg_entry[STG_WORD(w->port[i])] |= (0x3 << STG_BITS_SHIFT(w->port[i])); 11243 } 11244 11245 /* Saves default configuration of MISCCONFIG register in global structure 11246 and configures parity check and parity gen fields. */ 11247 SOC_IF_ERROR_RETURN(READ_MISCCONFIGr(unit, &rval)); 11248 w->parity_gen_en = soc_reg_field_get(unit, MISCCONFIGr, rval, PARITY_GEN_ENf); 11249 w->parity_chk_en = soc_reg_field_get(unit, MISCCONFIGr, rval, PARITY_CHK_ENf); 11250 11251 soc_reg_field_set(unit, MISCCONFIGr, &rval, PARITY_CHK_ENf, 1); 11252 soc_reg_field_set(unit, MISCCONFIGr, &rval, PARITY_GEN_ENf, 1); 11253 SOC_IF_ERROR_RETURN(WRITE_MISCCONFIGr(unit, rval)); 11254 11255 /* Write spanning tree group port state to hw. */ 11256 SOC_IF_ERROR_RETURN(soc_mem_write(unit, STG_TABm, MEM_BLOCK_ALL, 11257 1, stg_entry)); 11258 11259 /* Write port status on switch. */ 11260 soc_mem_pbmp_field_set(unit, EPC_LINK_BMAPm, &epc_entry, PORT_BITMAPf, &pbm); 11261 SOC_IF_ERROR_RETURN(WRITE_EPC_LINK_BMAPm(unit, MEM_BLOCK_ALL, 11262 0, &epc_entry)); 11263 11264 /* Mark priority 0 packets with red color. */ 11265 if (SOC_IS_TRIDENT3X(unit)) { 11266 SOC_IF_ERROR_RETURN(READ_PHB_MAPPING_TBL_1m(unit, MEM_BLOCK_ANY, 11267 0, &pri_map)); 11268 soc_mem_field32_set(unit, PHB_MAPPING_TBL_1m, &pri_map, CNGf, 1); 11269 SOC_IF_ERROR_RETURN(WRITE_PHB_MAPPING_TBL_1m(unit, MEM_BLOCK_ALL, 11270 0, &pri_map)); 11271 } else { 11272 SOC_IF_ERROR_RETURN(READ_ING_PRI_CNG_MAPm(unit, MEM_BLOCK_ANY, 11273 0, &pri_map)); 11274 soc_mem_field32_set(unit, ING_PRI_CNG_MAPm, &pri_map, CNGf, 1); 11275 SOC_IF_ERROR_RETURN(WRITE_ING_PRI_CNG_MAPm(unit, MEM_BLOCK_ALL, 11276 0, &pri_map)); 11277 } 11278 11279 return SOC_E_NONE; 11280 } 11281 11282 /* 11283 * Function: _bcm_td_wred_war_hw_state_restore 11284 * 11285 * Purpose: Restores default state of ports and other reg/mem's. 11286 */ 11287 11288 STATIC int 11289 _bcm_td_wred_war_hw_state_restore(int unit) 11290 { 11291 int i; 11292 int mode; 11293 uint32 rval; 11294 uint64 tx_ctrl; 11295 soc_pbmp_t pbmp; 11296 mac_driver_t *mac = NULL; 11297 _wred_war_ctrl_t *w; 11298 uint32 pri_map[SOC_MAX_MEM_FIELD_WORDS]; 11299 11300 int adv, max_speed = 0; 11301 mac = &soc_mac_x; 11302 w = &war; 11303 11304 SOC_PBMP_CLEAR(pbmp); 11305 11306 sal_memset(pri_map, 0, sizeof(pri_map)); 11307 11308 for (i = 0; i < SOC_WRED_WR_MAX_NUM_PORTS; i++) { 11309 if (w->port[i] == -1) { 11310 continue; 11311 } 11312 11313 if ((w->port_mode[i] != SOC_ENCAP_IEEE) && SOC_IS_TRIDENT(unit)) { 11314 SOC_IF_ERROR_RETURN 11315 (MAC_ENCAP_SET(mac, unit, w->port[i], w->port_mode[i])); 11316 11317 mode = soc_property_port_get(unit, w->port[i], 11318 spn_HIGIG2_HDR_MODE, 0); 11319 SOC_IF_ERROR_RETURN(soc_mem_field32_modify(unit, EGR_PORTm, 11320 w->port[i], HIGIG2f, mode)); 11321 SOC_IF_ERROR_RETURN(soc_reg_field32_modify(unit, XLPORT_CONFIGr, 11322 w->port[i], HIGIG2_MODEf, mode)); 11323 SOC_IF_ERROR_RETURN(soc_mem_field32_modify(unit, EGR_ING_PORTm, 11324 w->port[i], HIGIG2f, mode)); 11325 } 11326 SOC_IF_ERROR_RETURN 11327 (bcm_esw_port_loopback_set(unit, w->port[i], BCM_PORT_LOOPBACK_NONE)); 11328 11329 SOC_IF_ERROR_RETURN(bcm_esw_port_speed_max(unit, w->port[i], &max_speed)); 11330 BCM_IF_ERROR_RETURN(bcm_esw_port_autoneg_set(unit, w->port[i], w->autoneg[i])); 11331 /* if speed is 0, set the port speed to max. if port autoneg is enable, 11332 * port max speed may be 0. if port autoneg is enable and port max speed is 0, 11333 * bcm_esw_port_speed_set will be return SOC_E_CONFIG(-15). 11334 */ 11335 if (w->autoneg[i] == 0) { 11336 BCM_IF_ERROR_RETURN(bcm_esw_port_duplex_set(unit, w->port[i], w->duplex[i])); 11337 if (w->speed[i] != 0 || max_speed != 0) { 11338 BCM_IF_ERROR_RETURN(bcm_esw_port_speed_set(unit, w->port[i], w->speed[i])); 11339 } 11340 } 11341 adv = soc_property_port_get(unit, w->port[i], spn_PORT_INIT_ADV, -1); 11342 if (adv != -1) { 11343 BCM_IF_ERROR_RETURN(bcm_esw_port_advert_set(unit, w->port[i], w->advert[i])); 11344 } 11345 BCM_IF_ERROR_RETURN(bcm_esw_port_enable_set(unit, w->port[i], w->enable[i])); 11346 11347 SOC_IF_ERROR_RETURN(READ_XMAC_TX_CTRLr(unit, w->port[i], &tx_ctrl)); 11348 soc_reg64_field32_set(unit, XMAC_TX_CTRLr, &tx_ctrl, 11349 CRC_MODEf, w->port_crc_mode[i]); 11350 SOC_IF_ERROR_RETURN(WRITE_XMAC_TX_CTRLr(unit, w->port[i], tx_ctrl)); 11351 11352 /* Restore settings on port.*/ 11353 SOC_IF_ERROR_RETURN(soc_mem_write(unit, PORT_TABm, MEM_BLOCK_ALL, 11354 w->port[i], &w->port_entry[i])); 11355 11356 BCM_IF_ERROR_RETURN(bcm_esw_stat_clear(unit, w->port[i])); 11357 SOC_PBMP_PORT_ADD(pbmp, w->port[i]); 11358 } 11359 11360 SOC_IF_ERROR_RETURN(READ_MISCCONFIGr(unit, &rval)); 11361 soc_reg_field_set(unit, MISCCONFIGr, &rval, 11362 PARITY_CHK_ENf, w->parity_gen_en); 11363 soc_reg_field_set(unit, MISCCONFIGr, &rval, 11364 PARITY_GEN_ENf, w->parity_chk_en); 11365 SOC_IF_ERROR_RETURN(WRITE_MISCCONFIGr(unit, rval)); 11366 11367 /* Write default spanning tree group port states to hw. */ 11368 SOC_IF_ERROR_RETURN(soc_mem_write(unit, STG_TABm, MEM_BLOCK_ALL, 11369 1, w->stg_entry)); 11370 11371 /* Restore default value in ING_PR_CNG_MAP_TABLE. */ 11372 if (SOC_IS_TRIDENT3X(unit)) { 11373 SOC_IF_ERROR_RETURN(READ_PHB_MAPPING_TBL_1m(unit, MEM_BLOCK_ANY, 11374 0, &pri_map)); 11375 soc_mem_field32_set(unit, PHB_MAPPING_TBL_1m, &pri_map, CNGf, 0); 11376 SOC_IF_ERROR_RETURN(WRITE_PHB_MAPPING_TBL_1m(unit, MEM_BLOCK_ALL, 11377 0, &pri_map)); 11378 } else { 11379 SOC_IF_ERROR_RETURN(READ_ING_PRI_CNG_MAPm(unit, MEM_BLOCK_ANY, 11380 0, &pri_map)); 11381 soc_mem_field32_set(unit, ING_PRI_CNG_MAPm, &pri_map, CNGf, 0); 11382 SOC_IF_ERROR_RETURN(WRITE_ING_PRI_CNG_MAPm(unit, MEM_BLOCK_ALL, 11383 0, &pri_map)); 11384 } 11385 11386 /* Clear counters of war ports. */ 11387 SOC_IF_ERROR_RETURN(soc_counter_set32_by_port(unit, pbmp, 0)); 11388 11389 /* Write default port status to hw. */ 11390 SOC_IF_ERROR_RETURN(WRITE_EPC_LINK_BMAPm(unit, MEM_BLOCK_ALL, 11391 0, &w->epc_entry)); 11392 11393 return SOC_E_NONE; 11394 } 11395 11396 /* 11397 * Function: _bcm_td_wred_mem_war 11398 * 11399 * Purpose: Warkaound to recover WRED memories from 11400 * corrupted state to good state. 11401 * 11402 * Description : This logic sends 8 unicast packets that are larger 11403 * than 1 cell and contain a bad crc from below ports 11404 * to put WRED memories in good state. 11405 * 11406 * - Packet 1 ingresses on any port in the x-pipe and is supposed 11407 * to be switched to a non-extended queuing port in the x-pipe 11408 * - Packet 2 ingresses on any port in the x-pipe and is supposed 11409 * to be switched to a non-extended queuing port in the y-pipe 11410 * - Packet 3 ingresses on any port in the x-pipe and is supposed 11411 * to be switched to an extended queuing port in the x-pipe 11412 * - Packet 4 ingresses on any port in the x-pipe and is supposed 11413 * to be switched to an extended queuing port in the y-pipe 11414 * 11415 * - Packet 5 ingresses on any port in the y-pipe and is supposed 11416 * to be switched to a non-extended queuing port in the x-pipe 11417 * - Packet 6 ingresses on any port in the y-pipe and is supposed 11418 * to be switched to a non-extended queuing port in the y-pip 11419 * - Packet 7 ingresses on any port in the y-pipe and is supposed 11420 * to be switched to an extended queuing port in the x-pipe 11421 * - Packet 8 ingresses on any port in the y-pipe and is supposed 11422 * to be switched to an extended queuing port in the y-pipe 11423 */ 11424 int 11425 _bcm_td_wred_mem_war(int unit) 11426 { 11427 int rv = SOC_E_NONE; 11428 int i, j; 11429 int l2_flags; 11430 int pkt_flags; 11431 bcm_pkt_t *tx_pkt; 11432 bcm_mac_t mac = {0x00, 0x00, 0x00, 0x00, 0x00, 0x11}; 11433 bcm_mac_t dstmac, srcmac; 11434 l2x_entry_t l2x_entry; 11435 _wred_war_ctrl_t *w; 11436 11437 w = &war; 11438 11439 sal_memset(&l2x_entry, 0, sizeof (l2x_entry)); 11440 sal_memset(dstmac, 0, sizeof (dstmac)); 11441 sal_memset(srcmac, 0, sizeof (srcmac)); 11442 11443 /* Selects one regular port and one extented queue port from each pipeline 11444 * and configures wred workaround settings on selected ports and on switch. 11445 */ 11446 BCM_IF_ERROR_RETURN(_bcm_td_wred_war_ports_select(unit)); 11447 BCM_IF_ERROR_RETURN(_bcm_td_wred_war_configure(unit)); 11448 11449 11450 if (SOC_IS_TRIDENT(unit)) { 11451 /* Clears stray entries. */ 11452 l2_flags = BCM_L2_REPLACE_DELETE | BCM_L2_REPLACE_MATCH_STATIC | 11453 BCM_L2_REPLACE_VLAN_AND_VPN_TYPE; 11454 rv = bcm_esw_l2_replace(unit, l2_flags, NULL, -1, -1, -1); 11455 if (rv != BCM_E_NONE) { 11456 BCM_IF_ERROR_RETURN(_bcm_td_wred_war_hw_state_restore(unit)); 11457 return rv; 11458 } 11459 11460 /* Adds L2 entries in L2 table. */ 11461 soc_L2Xm_field32_set(unit, &l2x_entry, KEY_TYPEf, 0); 11462 soc_L2Xm_field32_set(unit, &l2x_entry, STATIC_BITf, 1); 11463 soc_L2Xm_field32_set(unit, &l2x_entry, VALIDf, 1); 11464 soc_L2Xm_field32_set(unit, &l2x_entry, VLAN_IDf, 1); 11465 for (i = 0; i < SOC_WRED_WR_MAX_NUM_PORTS; i++) { 11466 if (w->port[i] == -1) { 11467 continue; 11468 } 11469 MAC_LSB_SHIFT(dstmac, mac, i); 11470 soc_L2Xm_mac_addr_set(unit,&l2x_entry, MAC_ADDRf, dstmac); 11471 soc_L2Xm_field32_set(unit, &l2x_entry, PORT_NUMf, w->port[i]); 11472 soc_mem_insert(unit, L2Xm, MEM_BLOCK_ALL, (void *)&l2x_entry); 11473 } 11474 } 11475 11476 /* Allocates memory for packet. */ 11477 pkt_flags = BCM_TX_CRC_APPEND | BCM_TX_NO_PAD; 11478 rv = bcm_pkt_alloc(unit, WRED_MIN_PKT_SIZE, pkt_flags, &tx_pkt); 11479 if (rv != BCM_E_NONE) { 11480 BCM_IF_ERROR_RETURN(_bcm_td_wred_war_hw_state_restore(unit)); 11481 return rv; 11482 } 11483 11484 /* Configure packet parameters.*/ 11485 tx_pkt->unit = unit; 11486 tx_pkt->call_back = 0; 11487 tx_pkt->blk_count = 1; 11488 tx_pkt->_vtag[0] = 0x81; 11489 tx_pkt->_vtag[1] = 0x00; 11490 tx_pkt->_vtag[2] = 0x00; 11491 tx_pkt->_vtag[3] = 0x01; 11492 tx_pkt->flags |= BCM_PKT_F_NO_VTAG; 11493 tx_pkt->opcode = BCM_HG_OPCODE_UC; 11494 11495 /* This logic prepares 8 SOBMH packets with different src 11496 * and dst mac addresses and transmits packets from regular ports. 11497 */ 11498 for (i = 0; i < SOC_WRED_WR_MAX_NUM_PORTS; i++) { 11499 if ((w->port[i] == -1) || (i == 1) || (i == 3)) { 11500 /* Skip if the port is extended port. 11501 * Send packets only from regular port. 11502 */ 11503 continue; 11504 } 11505 MAC_LSB_SHIFT(srcmac, mac, i); 11506 BCM_PKT_HDR_SMAC_SET(tx_pkt, srcmac); 11507 BCM_PKT_PORT_SET(tx_pkt, w->port[i], FALSE, FALSE); 11508 11509 for (j = 0; j < SOC_WRED_WR_MAX_NUM_PORTS; j++) { 11510 if ((w->port[j] == -1)) { 11511 continue; 11512 } 11513 11514 MAC_LSB_SHIFT(dstmac, mac, j); 11515 BCM_PKT_HDR_DMAC_SET(tx_pkt, dstmac); 11516 11517 if (SOC_IS_TITAN(unit)) { 11518 tx_pkt->flags |= BCM_PKT_F_HGHDR; 11519 tx_pkt->flags |= BCM_TX_SRC_MOD; 11520 tx_pkt->src_mod = 2; /* Some randum value. */ 11521 tx_pkt->src_port = 0; 11522 tx_pkt->dest_port = w->port[j]; 11523 tx_pkt->dest_mod = (j > 1) ? 1 : 0; /* To handle DUAL_MODID's. */ 11524 } 11525 11526 rv = bcm_esw_tx(unit, tx_pkt, NULL); 11527 if (rv <= -1) { 11528 goto cleanup; 11529 } 11530 } 11531 } 11532 11533 cleanup: 11534 /* Frees packet pointer. */ 11535 rv = bcm_pkt_free(unit, tx_pkt); 11536 11537 if (SOC_IS_TRIDENT(unit)) { 11538 /* Delete L2 entries. */ 11539 for (i = 0; i < SOC_WRED_WR_MAX_NUM_PORTS; i++) { 11540 if (w->port[i] == -1) { 11541 continue; 11542 } 11543 MAC_LSB_SHIFT(dstmac, mac, i); 11544 soc_L2Xm_mac_addr_set(unit,&l2x_entry, MAC_ADDRf, dstmac); 11545 soc_L2Xm_field32_set(unit, &l2x_entry, PORT_NUMf, w->port[i]); 11546 SOC_IF_ERROR_RETURN(soc_mem_delete(unit, L2Xm, 11547 MEM_BLOCK_ANY, (void *)&l2x_entry)); 11548 } 11549 } 11550 11551 BCM_IF_ERROR_RETURN(_bcm_td_wred_war_hw_state_restore(unit)); 11552 11553 return rv; 11554 } 11555 #else /* BCM_TRIDENT_SUPPORT */ 11556 int _td_cosq_not_empty; 11557 #endif /* BCM_TRIDENT_SUPPORT */