cosq.c (12138B)
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 * File: cosq.c 8 */ 9 10 #include <soc/defs.h> 11 #if defined(BCM_HERCULES_SUPPORT) 12 #include <sal/core/libc.h> 13 #include <shared/bsl.h> 14 #include <soc/drv.h> 15 #include <soc/scache.h> 16 #include <soc/debug.h> 17 #include <soc/hercules.h> 18 19 #include <bcm/error.h> 20 #include <bcm/cosq.h> 21 #include <bcm/module.h> 22 23 #include <bcm_int/esw/mbcm.h> 24 #include <bcm_int/esw/hercules.h> 25 26 #ifdef BCM_WARM_BOOT_SUPPORT 27 #include <bcm_int/esw/switch.h> 28 #endif /* BCM_WARM_BOOT_SUPPORT */ 29 30 static int _num_cosq[SOC_MAX_NUM_DEVICES]; 31 32 #ifdef BCM_WARM_BOOT_SUPPORT 33 34 #define BCM_WB_VERSION_1_0 SOC_SCACHE_VERSION(1,0) 35 #define BCM_WB_DEFAULT_VERSION BCM_WB_VERSION_1_0 36 37 /* 38 * Function: 39 * _bcm_hercules_cosq_reinit 40 * Purpose: 41 * Recover COSQ software state. 42 * Parameters: 43 * unit - Unit number. 44 * Returns: 45 * BCM_E_XXX 46 */ 47 STATIC int 48 _bcm_hercules_cosq_reinit(int unit) 49 { 50 int rv; 51 soc_scache_handle_t scache_handle; 52 uint8 *cosq_scache_ptr; 53 uint32 num_cosq; 54 55 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 0); 56 rv = _bcm_esw_scache_ptr_get(unit, scache_handle, FALSE, 57 0, &cosq_scache_ptr, 58 BCM_WB_DEFAULT_VERSION, NULL); 59 60 if (rv == BCM_E_NOT_FOUND) { 61 cosq_scache_ptr = NULL; 62 } else if (BCM_FAILURE(rv)) { 63 return rv; 64 } 65 66 if (cosq_scache_ptr != NULL) { 67 /* Number COSQ */ 68 sal_memcpy(&num_cosq, cosq_scache_ptr, sizeof(num_cosq)); 69 _num_cosq[unit] = num_cosq; 70 71 } else { 72 int cos, lossless; 73 74 /* Pick from config */ 75 lossless = soc_property_get(unit, spn_LOSSLESS_MODE, 0); 76 cos = soc_property_get(unit, spn_BCM_NUM_COS, BCM_COS_DEFAULT); 77 78 if (cos < 1) { 79 cos = 1; 80 } else if (lossless && cos > 4) { 81 cos = 4; 82 } else if (cos > NUM_COS(unit)) { 83 cos = NUM_COS(unit); 84 } 85 _num_cosq[unit] = cos; 86 } 87 88 return BCM_E_NONE; 89 } 90 #endif /* BCM_WARM_BOOT_SUPPORT */ 91 92 int 93 bcm_hercules_cosq_init(int unit) 94 { 95 int lossless, num_cos; 96 #ifdef BCM_WARM_BOOT_SUPPORT 97 int rv; 98 soc_scache_handle_t scache_handle; 99 uint32 cosq_scache_size; 100 uint8 *cosq_scache_ptr; 101 #endif /* BCM_WARM_BOOT_SUPPORT */ 102 103 #ifdef BCM_WARM_BOOT_SUPPORT 104 /* Warm boot level 2 cache size */ 105 cosq_scache_size = sizeof(uint32); /* Number COSQ */ 106 107 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 0); 108 rv = _bcm_esw_scache_ptr_get(unit, scache_handle, 109 (0 == SOC_WARM_BOOT(unit)), 110 cosq_scache_size, &cosq_scache_ptr, 111 BCM_WB_DEFAULT_VERSION, NULL); 112 if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) { 113 return rv; 114 } 115 116 if (SOC_WARM_BOOT(unit)) { 117 return _bcm_hercules_cosq_reinit(unit); 118 } 119 #endif /* BCM_WARM_BOOT_SUPPORT */ 120 121 lossless = soc_property_get(unit, spn_LOSSLESS_MODE, 0); 122 123 num_cos = soc_property_get(unit, spn_BCM_NUM_COS, BCM_COS_DEFAULT); 124 125 if (num_cos < 1) { 126 num_cos = 1; 127 } else if (lossless && num_cos > 4) { 128 num_cos = 4; 129 } else if (num_cos > NUM_COS(unit)) { 130 num_cos = NUM_COS(unit); 131 } 132 133 return bcm_hercules_cosq_config_set(unit, num_cos); 134 } 135 136 int 137 bcm_hercules_cosq_config_set(int unit, int numq) 138 { 139 int lossless, num_ports; 140 int cos, prio, ratio, remain; 141 soc_port_t port; 142 143 /* Validate cosq num */ 144 if (numq < 1) { 145 return BCM_E_PARAM; 146 } 147 148 lossless = soc_property_get(unit, spn_LOSSLESS_MODE, 0); 149 150 SOC_PBMP_COUNT(PBMP_HG_ALL(unit), num_ports); 151 152 PBMP_ALL_ITER(unit, port) { 153 SOC_IF_ERROR_RETURN 154 (soc_hercules15_mmu_limits_config(unit, port, num_ports, 155 numq, lossless)); 156 } 157 158 /* Map the eight internal priority levels to the active cosqs */ 159 ratio = 8 / numq; 160 remain = 8 % numq; 161 cos = 0; 162 for (prio = 0; prio < 8; prio++) { 163 BCM_IF_ERROR_RETURN 164 (bcm_hercules_cosq_mapping_set(unit, -1, prio, cos)); 165 if ((prio + 1) == (((cos + 1) * ratio) + 166 ((remain < (numq - cos)) ? 0 : 167 (remain - (numq - cos) + 1)))) { 168 cos++; 169 } 170 } 171 172 _num_cosq[unit] = numq; 173 174 return BCM_E_NONE; 175 } 176 177 int 178 bcm_hercules_cosq_config_get(int unit, int *numq) 179 { 180 if (_num_cosq[unit] == 0) { 181 return BCM_E_INIT; 182 } 183 184 if (numq != NULL) { 185 *numq = _num_cosq[unit]; 186 } 187 188 return BCM_E_NONE; 189 } 190 191 int 192 bcm_hercules_cosq_mapping_set(int unit, bcm_port_t port, 193 bcm_cos_t priority, bcm_cos_queue_t cosq) 194 { 195 soc_field_t f; 196 uint32 reg, oreg; 197 198 if (cosq < 0 || cosq >= NUM_COS(unit)) { 199 return BCM_E_PARAM; 200 } 201 switch (priority) { 202 case 0: f = FIELD0f; break; 203 case 1: f = FIELD1f; break; 204 case 2: f = FIELD2f; break; 205 case 3: f = FIELD3f; break; 206 case 4: f = FIELD4f; break; 207 case 5: f = FIELD5f; break; 208 case 6: f = FIELD6f; break; 209 case 7: f = FIELD7f; break; 210 default: return BCM_E_PARAM; 211 } 212 213 if (port == -1) { 214 PBMP_HG_ITER(unit, port) { 215 SOC_IF_ERROR_RETURN(READ_ING_COS_MAPr(unit, port, ®)); 216 oreg = reg; 217 soc_reg_field_set(unit, ING_COS_MAPr, ®, f, cosq); 218 if (reg != oreg) { 219 SOC_IF_ERROR_RETURN(WRITE_ING_COS_MAPr(unit, port, reg)); 220 } 221 } 222 } else if (SOC_PORT_VALID(unit, port) && IS_HG_PORT(unit, port)) { 223 SOC_IF_ERROR_RETURN(READ_ING_COS_MAPr(unit, port, ®)); 224 oreg = reg; 225 soc_reg_field_set(unit, ING_COS_MAPr, ®, f, cosq); 226 if (reg != oreg) { 227 SOC_IF_ERROR_RETURN(WRITE_ING_COS_MAPr(unit, port, reg)); 228 } 229 } else { 230 return BCM_E_PORT; 231 } 232 233 return BCM_E_NONE; 234 } 235 236 int 237 bcm_hercules_cosq_mapping_get(int unit, bcm_port_t port, 238 bcm_cos_t priority, bcm_cos_queue_t *cosq) 239 { 240 soc_field_t f; 241 uint32 reg; 242 243 switch (priority) { 244 case 0: f = FIELD0f; break; 245 case 1: f = FIELD1f; break; 246 case 2: f = FIELD2f; break; 247 case 3: f = FIELD3f; break; 248 case 4: f = FIELD4f; break; 249 case 5: f = FIELD5f; break; 250 case 6: f = FIELD6f; break; 251 case 7: f = FIELD7f; break; 252 default: return BCM_E_PARAM; 253 } 254 255 if (port == -1) { 256 reg = 0; 257 PBMP_HG_ITER(unit, port) { 258 SOC_IF_ERROR_RETURN(READ_ING_COS_MAPr(unit, port, ®)); 259 break; 260 } 261 *cosq = soc_reg_field_get(unit, ING_COS_MAPr, reg, f); 262 } else if (SOC_PORT_VALID(unit, port) && IS_HG_PORT(unit, port)) { 263 SOC_IF_ERROR_RETURN(READ_ING_COS_MAPr(unit, port, ®)); 264 *cosq = soc_reg_field_get(unit, ING_COS_MAPr, reg, f); 265 } else { 266 return BCM_E_PORT; 267 } 268 return BCM_E_NONE; 269 } 270 271 int 272 bcm_hercules_cosq_port_sched_set(int unit, bcm_pbmp_t pbm, 273 int mode, const int weights[], int delay) 274 { 275 int port; 276 uint32 primod; 277 int mbits, cos; 278 279 COMPILER_REFERENCE(delay); 280 281 switch (mode) { 282 case BCM_COSQ_STRICT: 283 mbits = 0; 284 break; 285 case BCM_COSQ_WEIGHTED_ROUND_ROBIN: 286 mbits = 1; 287 /* 288 * Weight values for 5670/75 are 32-bits. 289 * If weight is 0, this queue is run in strict mode, 290 * others run in WRR mode. 291 */ 292 break; 293 default: 294 mbits = -1; 295 return BCM_E_PARAM; 296 } 297 298 PBMP_ITER(pbm, port) { 299 SOC_IF_ERROR_RETURN(READ_MMU_EGS_PRIMODr(unit, port, &primod)); 300 soc_reg_field_set(unit, MMU_EGS_PRIMODr, &primod, PRIf, mbits); 301 SOC_IF_ERROR_RETURN(WRITE_MMU_EGS_PRIMODr(unit, port, primod)); 302 } 303 304 if (mode == BCM_COSQ_WEIGHTED_ROUND_ROBIN) { 305 /* 306 * Weighted Fair Queueing scheduling 307 */ 308 PBMP_ITER(pbm, port) { 309 for (cos = 0; cos < 8; cos++) { 310 SOC_IF_ERROR_RETURN(WRITE_MMU_EGS_WGTCOSr(unit, port, cos, 311 weights[cos])); 312 } 313 } 314 } 315 316 return BCM_E_NONE; 317 } 318 319 int 320 bcm_hercules_cosq_port_sched_get(int unit, bcm_pbmp_t pbm, 321 int *mode, int weights[], int *delay) 322 { 323 uint32 primod, rval; 324 int port, mbits = -1, cos; 325 326 PBMP_ITER(pbm, port) { 327 SOC_IF_ERROR_RETURN(READ_MMU_EGS_PRIMODr(unit, port, &primod)); 328 mbits = soc_reg_field_get(unit, MMU_EGS_PRIMODr, primod, PRIf); 329 break; 330 } 331 332 switch (mbits) { 333 case 0: 334 *mode = BCM_COSQ_STRICT; 335 break; 336 case 1: 337 *mode = BCM_COSQ_WEIGHTED_ROUND_ROBIN; 338 for (cos = 0; cos < 8; cos++) { 339 SOC_IF_ERROR_RETURN(READ_MMU_EGS_WGTCOSr(unit, port, cos, &rval)); 340 weights[cos] = 341 soc_reg_field_get(unit, MMU_EGS_WGTCOSr, rval, WGTf); 342 } 343 break; 344 default: 345 return BCM_E_INTERNAL; 346 } 347 348 if (delay) { 349 *delay = 0; 350 } 351 return BCM_E_NONE; 352 } 353 354 int 355 bcm_hercules_cosq_sched_weight_max_get(int unit,int mode, 356 int *weight_max) 357 { 358 switch (mode) { 359 case BCM_COSQ_STRICT: 360 *weight_max = BCM_COSQ_WEIGHT_STRICT; 361 break; 362 case BCM_COSQ_WEIGHTED_ROUND_ROBIN: 363 *weight_max = BCM_COSQ_WEIGHT_UNLIMITED; 364 break; 365 default: 366 *weight_max = BCM_COSQ_WEIGHT_UNLIMITED; 367 return BCM_E_PARAM; 368 } 369 370 return BCM_E_NONE; 371 } 372 373 int 374 bcm_hercules_cosq_port_bandwidth_set(int unit, bcm_port_t port, 375 bcm_cos_queue_t cosq, 376 uint32 kbits_sec_min, 377 uint32 kbits_sec_max, 378 uint32 kbits_sec_burst, 379 uint32 flags) 380 { 381 return BCM_E_UNAVAIL; 382 } 383 384 int 385 bcm_hercules_cosq_port_bandwidth_get(int unit, bcm_port_t port, 386 bcm_cos_queue_t cosq, 387 uint32 *kbits_sec_min, 388 uint32 *kbits_sec_max, 389 uint32 *kbits_sec_burst, 390 uint32 *flags) 391 { 392 return BCM_E_UNAVAIL; 393 } 394 395 int 396 bcm_hercules_cosq_discard_set(int unit, uint32 flags) 397 { 398 return BCM_E_UNAVAIL; 399 } 400 401 int 402 bcm_hercules_cosq_discard_get(int unit, uint32 *flags) 403 { 404 return BCM_E_UNAVAIL; 405 } 406 407 int 408 bcm_hercules_cosq_discard_port_set(int unit, bcm_port_t port, 409 bcm_cos_queue_t cosq, 410 uint32 color, 411 int drop_start, 412 int drop_slope, 413 int average_time) 414 { 415 return BCM_E_UNAVAIL; 416 } 417 418 int 419 bcm_hercules_cosq_discard_port_get(int unit, bcm_port_t port, 420 bcm_cos_queue_t cosq, 421 uint32 color, 422 int *drop_start, 423 int *drop_slope, 424 int *average_time) 425 { 426 return BCM_E_UNAVAIL; 427 } 428 429 int 430 bcm_hercules_cosq_detach(int unit, int software_state_only) 431 { 432 return BCM_E_NONE; 433 } 434 435 #ifdef BCM_WARM_BOOT_SUPPORT 436 int 437 bcm_hercules_cosq_sync(int unit) 438 { 439 soc_scache_handle_t scache_handle; 440 uint8 *cosq_scache_ptr; 441 uint32 num_cosq; 442 443 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 0); 444 BCM_IF_ERROR_RETURN 445 (_bcm_esw_scache_ptr_get(unit, scache_handle, FALSE, 446 0, &cosq_scache_ptr, 447 BCM_WB_DEFAULT_VERSION, NULL)); 448 449 /* Number COSQ */ 450 num_cosq = _num_cosq[unit]; 451 sal_memcpy(cosq_scache_ptr, &num_cosq, sizeof(num_cosq)); 452 453 return BCM_E_NONE; 454 455 } 456 #endif /* BCM_WARM_BOOT_SUPPORT */ 457 458 #ifndef BCM_SW_STATE_DUMP_DISABLE 459 void 460 bcm_hercules_cosq_sw_dump(int unit) 461 { 462 LOG_CLI((BSL_META_U(unit, 463 "\nSW Information COSQ - Unit %d\n"), unit)); 464 LOG_CLI((BSL_META_U(unit, 465 " Number: %d\n"), _num_cosq[unit])); 466 467 return; 468 } 469 #endif /* BCM_SW_STATE_DUMP_DISABLE */ 470 #else /* BCM_HERCULES_SUPPORT */ 471 int _hercules_cosq_not_empty; 472 #endif /* BCM_HERCULES_SUPPORT */