tdm_td3_ovsb.c (53439B)
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 * $All Rights Reserved.$ 7 * 8 * TDM chip based printing and parsing functions 9 */ 10 #ifdef _TDM_STANDALONE 11 #include <tdm_top.h> 12 #else 13 #include <soc/tdm/core/tdm_top.h> 14 #endif 15 16 17 /** 18 @name: tdm_td3_ovsb_get_pkt_shaper_cal 19 @param: 20 @desc: [chip_specific] 21 22 Return pionter of the packet shaper scheduler. 23 */ 24 int * 25 tdm_td3_ovsb_get_pkt_shaper_cal(tdm_mod_t *_tdm, int spipe_num) 26 { 27 int * cal = NULL; 28 int cal_offset; 29 30 cal_offset = TD3_SHAPING_GRP_IDX_0 + spipe_num; 31 switch (_tdm->_core_data.vars_pkg.cal_id) { 32 case 0: cal = _tdm->_chip_data.cal_0.cal_grp[cal_offset]; break; 33 case 1: cal = _tdm->_chip_data.cal_1.cal_grp[cal_offset]; break; 34 case 2: cal = _tdm->_chip_data.cal_2.cal_grp[cal_offset]; break; 35 case 3: cal = _tdm->_chip_data.cal_3.cal_grp[cal_offset]; break; 36 default: 37 TDM_ERROR2("Invalid calendar ID %0d for %s\n", 38 _tdm->_core_data.vars_pkg.cal_id, 39 "tdm_td3_ovsb_get_pkt_shaper_cal()"); 40 cal = NULL; break; 41 } 42 43 return cal; 44 } 45 46 /** 47 @name: tdm_td3_ovsb_get_pkt_shaper_cal_prev 48 @param: 49 @desc: [chip_specific] 50 51 Return pionter of the previous packet shaper scheduler. 52 */ 53 int * 54 tdm_td3_ovsb_get_pkt_shaper_cal_prev(tdm_mod_t *_tdm, int spipe_num) 55 { 56 int * cal = NULL; 57 int cal_offset; 58 59 cal_offset = TD3_SHAPING_GRP_IDX_0 + spipe_num; 60 switch (_tdm->_core_data.vars_pkg.cal_id) { 61 case 0: cal = _tdm->_prev_chip_data.cal_0.cal_grp[cal_offset]; break; 62 case 1: cal = _tdm->_prev_chip_data.cal_1.cal_grp[cal_offset]; break; 63 case 2: cal = _tdm->_prev_chip_data.cal_2.cal_grp[cal_offset]; break; 64 case 3: cal = _tdm->_prev_chip_data.cal_3.cal_grp[cal_offset]; break; 65 default: 66 TDM_ERROR2("Invalid calendar ID %0d for %s\n", 67 _tdm->_core_data.vars_pkg.cal_id, 68 "tdm_td3_ovsb_get_pkt_shaper_cal_prev()"); 69 cal = NULL; break; 70 } 71 72 return cal; 73 } 74 75 /** 76 @name: tdm_td3_ovsb_get_spipe_grp_range 77 @param: 78 79 Return ovsb group range [grp_lo, grp_hi] for given subpipe. 80 */ 81 void 82 tdm_td3_ovsb_get_spipe_grp_range(tdm_mod_t *_tdm, int spipe, int *lo, int *hi) 83 { 84 int grp_per_spipe, grp_lo = 0, grp_hi = 0; 85 tdm_calendar_t *cal; 86 87 cal = tdm_td3_cmn_get_pipe_cal(_tdm); 88 if (cal != NULL) { 89 if (spipe >= 0 && spipe < TD3_NUM_SPIPE && cal->grp_num > 0) { 90 grp_per_spipe = cal->grp_num / TD3_NUM_SPIPE; 91 grp_lo = (spipe * grp_per_spipe) % cal->grp_num; 92 grp_hi = (grp_lo + grp_per_spipe - 1) % cal->grp_num; 93 } 94 } 95 (*lo) = grp_lo; 96 (*hi) = grp_hi; 97 } 98 99 /** 100 @name: tdm_td3_ovsb_get_grp_spd 101 @param: 102 103 Return group speed of the given ovsb group in ethernet speed format. 104 If ovsb group is empty, return 0. 105 */ 106 int 107 tdm_td3_ovsb_get_grp_spd(tdm_mod_t *_tdm, int grp) 108 { 109 int prt, pos; 110 int param_token_empty; 111 tdm_calendar_t *cal; 112 113 param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports; 114 cal = tdm_td3_cmn_get_pipe_cal(_tdm); 115 if (cal == NULL) return 0; 116 117 if (grp >= 0 && grp < cal->grp_num) { 118 for (pos = 0; pos < cal->grp_len; pos++) { 119 prt = cal->cal_grp[grp][pos]; 120 if (prt != param_token_empty) { 121 return (tdm_td3_cmn_get_port_speed_eth(_tdm, prt)); 122 } 123 } 124 } 125 126 return 0; 127 } 128 129 /** 130 @name: tdm_td3_ovsb_get_grp_prt_cnt 131 @param: 132 133 Return number of active ports in the given oversub speed group. 134 If ovsb group is empty, return 0. 135 */ 136 int 137 tdm_td3_ovsb_get_grp_prt_cnt(tdm_mod_t *_tdm, int grp) 138 { 139 int prt, pos, prt_cnt = 0; 140 int param_token_empty; 141 tdm_calendar_t *cal; 142 143 param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports; 144 cal = tdm_td3_cmn_get_pipe_cal(_tdm); 145 if (cal == NULL) return prt_cnt; 146 147 if (grp >= 0 && grp < cal->grp_num) { 148 for (pos = 0; pos < cal->grp_len; pos++) { 149 prt = cal->cal_grp[grp][pos]; 150 if (prt != param_token_empty) prt_cnt++; 151 } 152 } 153 154 return prt_cnt; 155 } 156 157 /** 158 @name: tdm_td3_ovsb_get_grp_empty_cnt 159 @param: 160 161 Return the number of empty slots in the given ovsb group. 162 */ 163 int 164 tdm_td3_ovsb_get_grp_empty_cnt(tdm_mod_t *_tdm, int grp) 165 { 166 tdm_calendar_t *cal; 167 168 cal = tdm_td3_cmn_get_pipe_cal(_tdm); 169 if (cal == NULL) return 0; 170 171 return (cal->grp_len - tdm_td3_ovsb_get_grp_prt_cnt(_tdm, grp)); 172 } 173 174 /** 175 @name: tdm_td3_ovsb_get_prt_spipe 176 @param: 177 178 Return subpipe index of the given port. 179 -1: unassigned 180 n: subpipe index, 0 <= n < TD3_NUM_SPIPE 181 */ 182 int 183 tdm_td3_ovsb_get_prt_spipe(tdm_mod_t *_tdm, int port_token) 184 { 185 int pm, spipe = -1; 186 187 pm = tdm_td3_cmn_get_port_pm(_tdm, port_token); 188 if (pm >= 0 && pm < TD3_NUM_PM_MOD) { 189 spipe = _tdm->_chip_data.soc_pkg.soc_vars.td3.pm_ovs_halfpipe[pm]; 190 /* if (spipe >= 0 && spipe < TD3_NUM_SPIPE) return spipe; */ 191 } 192 193 return spipe; 194 } 195 196 /** 197 @name: tdm_td3_ovsb_get_prt_lane 198 @param: 199 200 Return relative lane index of the given port within PM. 201 */ 202 int 203 tdm_td3_ovsb_get_prt_lane(tdm_mod_t *_tdm, int prt) 204 { 205 if (prt >= _tdm->_chip_data.soc_pkg.soc_vars.fp_port_lo && 206 prt <= _tdm->_chip_data.soc_pkg.soc_vars.fp_port_hi) { 207 return ((prt - 1) % TD3_NUM_PM_LNS); 208 } 209 210 return 0; 211 } 212 213 /** 214 @name: tdm_td3_ovsb_get_pm_shaper_prt_stride 215 @param: 216 @desc: [chip_specific] 217 218 Return incremental distance between two consecutive port slots in 219 PM shaper calendar. 220 */ 221 int 222 tdm_td3_ovsb_get_pm_shaper_prt_stride(tdm_mod_t *_tdm, int prt) 223 { 224 int spd, stride; 225 226 spd = tdm_td3_cmn_get_port_speed_eth(_tdm, prt); 227 switch (spd) { 228 case SPEED_10G: stride = 8; break; 229 case SPEED_20G: stride = 4; break; 230 case SPEED_25G: stride = 4; break; 231 case SPEED_40G: stride = 2; break; 232 case SPEED_50G: stride = 2; break; 233 case SPEED_100G: stride = 1; break; 234 default: stride = 0; break; 235 } 236 /* for any speed less than 10G, take it as 10G */ 237 if (spd > 0 && spd < SPEED_10G) stride = 8; 238 239 return stride; 240 } 241 242 /** 243 @name: tdm_td3_ovsb_get_pm_shaper_prt_offset 244 @param: 245 @desc: [chip_specific] 246 247 Return port offset within pseudo PM shaper calendar. 248 */ 249 int 250 tdm_td3_ovsb_get_pm_shaper_prt_offset(tdm_mod_t *_tdm, int prt) 251 { 252 int ln_base, ln_offset; 253 254 ln_base = tdm_td3_ovsb_get_prt_lane(_tdm, prt); 255 switch (ln_base) { 256 case 0: ln_offset = 0; break; 257 case 1: ln_offset = 2; break; 258 case 2: ln_offset = 1; break; 259 case 3: ln_offset = 3; break; 260 default:ln_offset = 0; break; 261 } 262 263 return ln_offset; 264 } 265 266 /** 267 @name: tdm_td3_ovsb_get_pm_shaper_prt_pos 268 @param: 269 @desc: [chip_specific] 270 271 Return the n-th slot pos of the given port in pm shaper calendar. 272 */ 273 int 274 tdm_td3_ovsb_get_pm_shaper_prt_pos(tdm_mod_t *_tdm, int prt, int slot_cnt) 275 { 276 int pos, prt_offset, prt_stride, prt_spd, ln_base; 277 278 prt_offset = tdm_td3_ovsb_get_pm_shaper_prt_offset(_tdm, prt); 279 prt_stride = tdm_td3_ovsb_get_pm_shaper_prt_stride(_tdm, prt); 280 281 prt_spd = tdm_td3_cmn_get_port_speed_eth(_tdm, prt); 282 ln_base = tdm_td3_ovsb_get_prt_lane(_tdm, prt); 283 /* [chip_specific] (pre-opt) special case: 10G */ 284 if (prt_spd == SPEED_10G) { 285 switch (ln_base) { 286 case 1: prt_offset += 2*prt_stride; break; 287 case 2: prt_offset += prt_stride; break; 288 default: break; 289 } 290 } 291 /* [chip_specific] (pre-opt) special case: 20G */ 292 else if (prt_spd == SPEED_20G) { 293 if (slot_cnt == 2 || slot_cnt == 3) prt_offset += 2; 294 } 295 /* [chip_specific] (pre-opt) special case: 40G */ 296 else if (prt_spd == SPEED_40G) { 297 if (slot_cnt >= 4 && slot_cnt <= 7) prt_offset += 2; 298 } 299 300 /* calculate slot position */ 301 pos = (prt_offset + prt_stride * slot_cnt) % TD3_SHAPER_NUM_PM_SLOTS; 302 303 return pos; 304 } 305 306 /** 307 @name: tdm_td3_ovsb_get_pkt_shaper_prt_pm_idx 308 @param: 309 310 Find an existing or available pm_idx in pkt_shaper 311 */ 312 int 313 tdm_td3_ovsb_get_pkt_shaper_prt_pm_idx(tdm_mod_t *_tdm, int prt) 314 { 315 int i, j, max_start_indx, distance, max_distance; 316 int prt_spipe, prt_pm, pos, pm_idx; 317 int *pkt_shaper_cal = NULL; 318 int pm_indx_avail[TD3_NUM_PMS_PER_SPIPE]; 319 int param_cal_id, param_token_empty; 320 321 param_cal_id = _tdm->_core_data.vars_pkg.cal_id; 322 param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports; 323 prt_pm = tdm_td3_cmn_get_port_pm(_tdm, prt); 324 325 prt_spipe = tdm_td3_ovsb_get_prt_spipe(_tdm, prt); 326 if (!(prt_spipe >= 0 && prt_spipe < TD3_NUM_SPIPE)) return FAIL; 327 328 pkt_shaper_cal = tdm_td3_ovsb_get_pkt_shaper_cal(_tdm, prt_spipe); 329 if (pkt_shaper_cal == NULL) return FAIL; 330 331 /* Case 1: there are sister ports of this port already in pkt scheduler, 332 which means find that PM and place port in the corresponding lanes. */ 333 pm_idx = -1; 334 for (i = 0; i < TD3_SHAPING_GRP_LEN; i++) { 335 if (pkt_shaper_cal[i] != param_token_empty) { 336 if (prt_pm == tdm_td3_cmn_get_port_pm(_tdm, pkt_shaper_cal[i])) { 337 /* Find that PM has already been placed */ 338 pm_idx = i % TD3_NUM_PMS_PER_SPIPE; 339 break; 340 } 341 } 342 } 343 344 /* Case 2: there is no sister port of this port already in pkt scheduler, 345 which means find an empty PM and place port in the corresponding lanes 346 Find an available PM */ 347 if (pm_idx == -1) { 348 for (i = 0; i < TD3_NUM_PMS_PER_SPIPE; i++) { 349 pm_indx_avail[i] = 1; 350 for (j = 0; j < TD3_NUM_PKT_SLOTS_PER_PM; j++) { 351 pos = (j * TD3_NUM_PMS_PER_SPIPE + i) % TD3_SHAPING_GRP_LEN; 352 if (pkt_shaper_cal[pos] != param_token_empty) { 353 pm_indx_avail[i] = 0; 354 break; 355 } 356 } 357 } 358 359 /* Find the biggest clump of 1's in pm_indx_avail array, and 360 choose the pm_idx in the middle of the clump */ 361 max_start_indx = 0; 362 distance = 0; 363 max_distance = 0; 364 for (i = 0; i < TD3_NUM_PMS_PER_SPIPE; i++) { 365 if (pm_indx_avail[i] == 1) { 366 distance = 0; 367 for (j = 0; j < TD3_NUM_PMS_PER_SPIPE; j++){ 368 if (pm_indx_avail[(i+j) % TD3_NUM_PMS_PER_SPIPE] == 1) { 369 distance++; 370 } else { 371 break; 372 } 373 } 374 if (distance > max_distance) { 375 max_start_indx = i; 376 max_distance = distance; 377 } 378 } 379 } 380 /* If all available make it 0, else middle of the clump*/ 381 pm_idx = (max_distance == TD3_NUM_PMS_PER_SPIPE) ? 0 : 382 ((max_start_indx + TD3_NUM_PMS_PER_SPIPE) % TD3_NUM_PMS_PER_SPIPE); 383 384 if (pm_indx_avail[pm_idx] == 0) { 385 pm_idx = -1; 386 TDM_ERROR4("%s, PIPE %d, pm %0d, port %0d\n", 387 "Failed to find an available PM", 388 param_cal_id, prt_pm, prt); 389 } 390 } 391 392 if (pm_idx == -1) { 393 TDM_ERROR4("%s, PIPE %d, pm %0d, phy_port %0d\n", 394 "Failed to find an available PM", 395 param_cal_id, prt_pm, prt); 396 } 397 398 return pm_idx; 399 } 400 401 /** 402 @name: tdm_td3_ovsb_get_pkt_shaper_prt_pos 403 @param: 404 @desc: [chip_specific] 405 406 For the n-th slot in pm_shaper_calendar, calculate the corresponding slot 407 postion in packet_shaper_calendar. 408 */ 409 int 410 tdm_td3_ovsb_get_pkt_shaper_prt_pos(tdm_mod_t *_tdm, int prt, 411 int pm_shaper_slot_idx) 412 { 413 int pos = -1; 414 int num_blocks, block_idx = 0, block_offset, lane, lane_offset, pm_offset; 415 416 /* calc block_offset: one block is one minimum repetition pattern */ 417 num_blocks = TD3_SHAPING_GRP_LEN / TD3_NUM_PHY_PORTS_PER_SPIPE; 418 if (num_blocks > 0) { 419 block_idx = (pm_shaper_slot_idx / TD3_NUM_PM_LNS) % num_blocks; 420 } 421 block_offset = block_idx * TD3_NUM_PHY_PORTS_PER_SPIPE; 422 423 /* calc lane_offset: one subblock contains slots with the same lane num */ 424 lane = pm_shaper_slot_idx % TD3_NUM_PM_LNS; /* lane num in pm_shaper_cal */ 425 switch (lane) { 426 case 0: lane_offset = 0; break; /* subport 0 */ 427 case 1: lane_offset = 1*TD3_NUM_PMS_PER_SPIPE; break; /* subport 2 */ 428 case 2: lane_offset = 2*TD3_NUM_PMS_PER_SPIPE; break; /* subport 1 */ 429 default: lane_offset = 3*TD3_NUM_PMS_PER_SPIPE; break; /* subport 3 */ 430 } 431 432 /* calc pm_offset: within each subblock, slot is determined by pm_offset */ 433 pm_offset = tdm_td3_ovsb_get_pkt_shaper_prt_pm_idx(_tdm, prt); 434 if (pm_offset == -1) return pos; 435 436 /* calculate slot position of pm shaper slot in packet shaper calendar */ 437 pos = (block_offset + lane_offset + pm_offset) % TD3_SHAPING_GRP_LEN; 438 439 return pos; 440 } 441 442 /** 443 @name: tdm_td3_ovsb_apply_constraints_init 444 @param: 445 @desc: [chip_specific] 446 447 Partition OVSB PMs into 2 halfpipes 448 */ 449 int 450 tdm_td3_ovsb_apply_constraints_init(tdm_mod_t *_tdm) 451 { 452 int i, j, prt, prt_pm, num_spd_types = 0, result = PASS; 453 int param_cal_id; 454 int *pm2spipe_map = NULL; 455 m_tdm_pipe_info_t *pipe_info; 456 457 param_cal_id = _tdm->_core_data.vars_pkg.cal_id; 458 pm2spipe_map = _tdm->_chip_data.soc_pkg.soc_vars.td3.pm_ovs_halfpipe; 459 pipe_info = &(_tdm->_core_data.vars_pkg.pipe_info); 460 461 for (i = 0; i < MAX_SPEED_TYPES; i++) { 462 if (pipe_info->os_spd_en[i]) num_spd_types++; 463 } 464 465 /* check necessary condition */ 466 tdm_cmn_chk_pipe_os_spd_types(_tdm); 467 468 /* Restriction 13: No port configurations with more than 4 port speed 469 * classes are supported. 470 */ 471 if (num_spd_types > 5) { 472 result = FAIL; 473 TDM_ERROR4("%s, PIPE %d, num_spd_types %0d, limit %0d\n", 474 "Failed in ovsb partition, number of speed types overflow", 475 param_cal_id, num_spd_types, 4); 476 } 477 /* Restriction 14: The only supported port configurations with 4 port 478 speed classes are: 479 10G/20G/40G/100G 480 10G/25G/50G/100G 481 Rule: Group PMs with 25G/50G ports in HP0 and PMs with 20G/40G in HP1. 482 */ 483 if (num_spd_types == 4) { 484 if ((pipe_info->os_spd_en[TDM_SPEED_IDX_10G] && 485 pipe_info->os_spd_en[TDM_SPEED_IDX_20G] && 486 pipe_info->os_spd_en[TDM_SPEED_IDX_40G] && 487 pipe_info->os_spd_en[TDM_SPEED_IDX_100G]) || 488 (pipe_info->os_spd_en[TDM_SPEED_IDX_10G] && 489 pipe_info->os_spd_en[TDM_SPEED_IDX_25G] && 490 pipe_info->os_spd_en[TDM_SPEED_IDX_50G] && 491 pipe_info->os_spd_en[TDM_SPEED_IDX_100G])) { 492 TDM_PRINT0("TDM: Apply [Restriction 14]\n"); 493 for (i = 0; i < MAX_SPEED_TYPES; i++) { 494 if (!(pipe_info->os_spd_en[i])) continue; 495 if (i == TDM_SPEED_IDX_25G || i == TDM_SPEED_IDX_50G) { 496 for (j = 0; j < pipe_info->os_prt_cnt[i]; j++) { 497 prt = pipe_info->os_prt[i][j]; 498 prt_pm = tdm_td3_cmn_get_port_pm(_tdm, prt); 499 pm2spipe_map[prt_pm] = 0; 500 } 501 } else if (i == TDM_SPEED_IDX_20G || i == TDM_SPEED_IDX_40G) { 502 for (j = 0; j < pipe_info->os_prt_cnt[i]; j++) { 503 prt = pipe_info->os_prt[i][j]; 504 prt_pm = tdm_td3_cmn_get_port_pm(_tdm, prt); 505 pm2spipe_map[prt_pm] = 1; 506 } 507 } 508 } 509 } else { 510 result = FAIL; 511 TDM_ERROR1("%s, invalid config with 4 speed types\n", 512 "Failed in ovsb partition"); 513 } 514 } 515 /* Restriction 15: All port configurations with 1-3 port speed classes 516 * are supported, except configurations that contain both 517 * 20G and 25G port speeds. 518 * Rule: Group PMs with 25G/50G ports in HP0 and PMs with 20G/40G in HP1. 519 */ 520 if (num_spd_types > 1 && num_spd_types <= 3) { 521 if ((pipe_info->os_spd_en[TDM_SPEED_IDX_20G] || 522 pipe_info->os_spd_en[TDM_SPEED_IDX_40G]) && 523 (pipe_info->os_spd_en[TDM_SPEED_IDX_25G] || 524 pipe_info->os_spd_en[TDM_SPEED_IDX_50G])) { 525 TDM_PRINT0("Apply [Restriction 15]\n"); 526 for (i = 0; i < MAX_SPEED_TYPES; i++) { 527 if (!(pipe_info->os_spd_en[i])) continue; 528 if (i == TDM_SPEED_IDX_25G || i == TDM_SPEED_IDX_50G) { 529 for (j = 0; j < pipe_info->os_prt_cnt[i]; j++) { 530 prt = pipe_info->os_prt[i][j]; 531 prt_pm = tdm_td3_cmn_get_port_pm(_tdm, prt); 532 pm2spipe_map[prt_pm] = 0; 533 } 534 } else if (i == TDM_SPEED_IDX_20G || i == TDM_SPEED_IDX_40G) { 535 for (j = 0; j < pipe_info->os_prt_cnt[i]; j++) { 536 prt = pipe_info->os_prt[i][j]; 537 prt_pm = tdm_td3_cmn_get_port_pm(_tdm, prt); 538 pm2spipe_map[prt_pm] = 1; 539 } 540 } 541 } 542 } 543 } 544 545 return result; 546 } 547 548 /** 549 @name: tdm_td3_ovsb_apply_constraints_flex 550 @param: 551 @desc: [chip_specific] 552 553 Partition OVSB PMs into 2 halfpipes. 554 */ 555 int 556 tdm_td3_ovsb_apply_constraints_flex(tdm_mod_t *_tdm) 557 { 558 int i, prt, prt_pm, num_spd_types = 0, result = PASS; 559 int spipe, pos, grp, grp_lo = 0, grp_hi = 0; 560 int param_cal_id, param_token_empty; 561 int *pm2spipe_map = NULL; 562 m_tdm_pipe_info_t *pipe_info; 563 tdm_calendar_t *cal; 564 565 param_cal_id = _tdm->_core_data.vars_pkg.cal_id; 566 param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports; 567 pm2spipe_map = _tdm->_chip_data.soc_pkg.soc_vars.td3.pm_ovs_halfpipe; 568 pipe_info = &(_tdm->_core_data.vars_pkg.pipe_info); 569 570 /* get pipe calendar */ 571 cal = tdm_td3_cmn_get_pipe_cal(_tdm); 572 if (cal == NULL) return result; 573 574 /* Restriction 13: No port configurations with more than 4 port speed 575 * classes are supported. 576 */ 577 for (i = 0; i < MAX_SPEED_TYPES; i++) { 578 if (pipe_info->os_spd_en[i]) num_spd_types++; 579 } 580 if (num_spd_types > 4) { 581 result = FAIL; 582 TDM_ERROR4("%s, PIPE %d, num_spd_types %0d, limit %0d\n", 583 "Failed in ovsb partition, number of speed types overflow", 584 param_cal_id, num_spd_types, 4); 585 } 586 587 /* retrieve subpipe number for allocated PMs */ 588 for (spipe = 0; spipe < TD3_NUM_SPIPE; spipe++) { 589 tdm_td3_ovsb_get_spipe_grp_range(_tdm, spipe, &grp_lo, &grp_hi); 590 for (grp = grp_lo; grp <= grp_hi; grp++) { 591 for (pos = 0; pos < cal->grp_len; pos++) { 592 prt = cal->cal_grp[grp][pos]; 593 if (prt != param_token_empty) { 594 prt_pm = tdm_td3_cmn_get_port_pm(_tdm, prt); 595 pm2spipe_map[prt_pm] = spipe; 596 } 597 } 598 } 599 } 600 601 return result; 602 } 603 604 /** 605 @name: tdm_td3_ovsb_init_pmlist 606 @param: 607 */ 608 void 609 tdm_td3_ovsb_init_pmlist(tdm_mod_t *_tdm, tdm_td3_ovsb_pm_t *pmlist, int pmlist_size) 610 { 611 int i, spd_idx, pos, prt, pm, spd; 612 m_tdm_pipe_info_t *pipe_info; 613 614 /* reset pmlist */ 615 for (i = 0; i < pmlist_size; i++) { 616 pmlist[i].pm_en = 0; 617 pmlist[i].pm_num = 0; 618 pmlist[i].pm_bw = 0; 619 pmlist[i].pm_max_spd = 0; 620 } 621 622 /* initialize pmlist based pipe_info */ 623 pipe_info = &(_tdm->_core_data.vars_pkg.pipe_info); 624 for (spd_idx = MAX_SPEED_TYPES - 1; spd_idx >=0 ; spd_idx--) { 625 if (pipe_info->os_spd_en[spd_idx]) { 626 for (pos = 0; pos < pipe_info->os_prt_cnt[spd_idx]; pos++) { 627 prt = pipe_info->os_prt[spd_idx][pos]; 628 pm = tdm_td3_cmn_get_port_pm(_tdm, prt); 629 spd = tdm_td3_cmn_get_port_speed(_tdm, prt); 630 if (pm >= 0 && pm < pmlist_size && spd > 0) { 631 pmlist[pm].pm_en = 1; 632 pmlist[pm].pm_num = pm; 633 pmlist[pm].pm_bw += spd; 634 pmlist[pm].pm_max_spd = (pmlist[pm].pm_max_spd < spd) ? 635 spd : pmlist[pm].pm_max_spd; 636 } 637 } 638 } 639 } 640 } 641 642 /** 643 @name: tdm_td3_ovsb_swap_pm 644 @param: 645 */ 646 void 647 tdm_td3_ovsb_swap_pm(tdm_mod_t *_tdm, tdm_td3_ovsb_pm_t *pmlist, int src, int dst) 648 { 649 tdm_td3_ovsb_pm_t pm_tmp; 650 651 pm_tmp.pm_en = pmlist[src].pm_en; 652 pm_tmp.pm_num = pmlist[src].pm_num; 653 pm_tmp.pm_bw = pmlist[src].pm_bw; 654 pm_tmp.pm_max_spd = pmlist[src].pm_max_spd; 655 656 pmlist[src].pm_en = pmlist[dst].pm_en; 657 pmlist[src].pm_num = pmlist[dst].pm_num; 658 pmlist[src].pm_bw = pmlist[dst].pm_bw; 659 pmlist[src].pm_max_spd = pmlist[dst].pm_max_spd; 660 661 pmlist[dst].pm_en = pm_tmp.pm_en; 662 pmlist[dst].pm_num = pm_tmp.pm_num; 663 pmlist[dst].pm_bw = pm_tmp.pm_bw; 664 pmlist[dst].pm_max_spd = pm_tmp.pm_max_spd; 665 } 666 667 /** 668 @name: tdm_td3_ovsb_gen_pm2spipe_map_static 669 @param: 670 @desc: [chip_specific] 671 672 Partition each PM into a subpipe. 673 -- pipe 0, pm[0 - 7], port[1 - 32]: hpipe 0 674 -- pipe 0, pm[8 -15], port[33- 64]: hpipe 1 675 -- pipe 1, pm[16-23], port[65- 96]: hpipe 0 676 -- pipe 1, pm[24-31], port[97- 128]: hpipe 1 677 */ 678 int 679 tdm_td3_ovsb_gen_pm2spipe_map_static(tdm_mod_t *_tdm) 680 { 681 int prt, pm, spipe_num, spd_idx, prt_idx; 682 int pms_per_pipe, pms_per_spipe; 683 int *pm2spipe_map = NULL; 684 m_tdm_pipe_info_t *pipe_info; 685 686 /* init variables */ 687 pm2spipe_map = _tdm->_chip_data.soc_pkg.soc_vars.td3.pm_ovs_halfpipe; 688 pipe_info = &(_tdm->_core_data.vars_pkg.pipe_info); 689 pms_per_pipe = _tdm->_chip_data.soc_pkg.pm_num_phy_modules / 690 TD3_NUM_PIPE; 691 pms_per_spipe= pms_per_pipe / TD3_NUM_SPIPE; 692 for (pm = 0; pm < TD3_NUM_PM_MOD; pm++) { 693 pm2spipe_map[pm] = -1; /* -1:unassigned, 0:hp0, 1:hp1 */ 694 } 695 696 /* partition PMs into subpipes */ 697 if (pms_per_pipe > 0 && pms_per_spipe > 0) { 698 for (spd_idx = 0; spd_idx < MAX_SPEED_TYPES; spd_idx++) { 699 if (pipe_info->os_spd_en[spd_idx]) { 700 for (prt_idx = 0; prt_idx < pipe_info->os_prt_cnt[spd_idx]; 701 prt_idx++) { 702 prt = pipe_info->os_prt[spd_idx][prt_idx]; 703 pm = tdm_td3_cmn_get_port_pm(_tdm, prt); 704 if (pm2spipe_map[pm] == -1) { 705 /* [chip_specific]: static mapping rule */ 706 spipe_num = (pm % pms_per_pipe) / pms_per_spipe; 707 pm2spipe_map[pm] = spipe_num; 708 TDM_PRINT2("TDM: partition PM %2d to subpipe %0d\n", 709 pm, spipe_num); 710 } 711 } 712 } 713 } 714 } 715 TDM_SML_BAR 716 717 return PASS; 718 } 719 720 /** 721 @name: tdm_td3_ovsb_gen_pm2spipe_map_dynamic 722 @param: 723 724 Partition each PM into a subpipe. 725 */ 726 int 727 tdm_td3_ovsb_gen_pm2spipe_map_dynamic(tdm_mod_t *_tdm) 728 { 729 int i, j, spd_max, idx_src, idx_dst, pm, pm_idx, result = PASS; 730 int spipe, dst_spipe, dst_spipe_bw, pms_per_spipe; 731 int spipe_bw[TD3_NUM_SPIPE], spipe_pm_cnt[TD3_NUM_SPIPE]; 732 tdm_td3_ovsb_pm_t pmlist[TD3_NUM_PHY_PM]; 733 int *pm2spipe_map = NULL; 734 735 /* initialize variables */ 736 pm2spipe_map = _tdm->_chip_data.soc_pkg.soc_vars.td3.pm_ovs_halfpipe; 737 pms_per_spipe = _tdm->_chip_data.soc_pkg.pm_num_phy_modules / 738 TD3_NUM_PIPE / TD3_NUM_SPIPE; 739 for (pm = 0; pm < TD3_NUM_PM_MOD; pm++) { 740 pm2spipe_map[pm] = -1; /* -1:unassigned, 0:hp0, 1:hp1 */ 741 } 742 for (spipe = 0; spipe < TD3_NUM_SPIPE; spipe++) { 743 spipe_bw[spipe] = 0; 744 spipe_pm_cnt[spipe] = 0; 745 } 746 747 /* step1: apply constraints by grouping certain PMs into same subpipe */ 748 if (_tdm->_chip_data.soc_pkg.flex_port_en == 1) { 749 if (tdm_td3_ovsb_apply_constraints_flex(_tdm) != PASS) result = FAIL; 750 } else { 751 if (tdm_td3_ovsb_apply_constraints_init(_tdm) != PASS) result = FAIL; 752 } 753 754 /* step2-1: construct pmlist */ 755 tdm_td3_ovsb_init_pmlist(_tdm, pmlist, TD3_NUM_PHY_PM); 756 757 /* step2-2: calculate bw for each subpipe in prepartition */ 758 for (pm = 0; pm < TD3_NUM_PHY_PM && pm < TD3_NUM_PM_MOD; pm++) { 759 spipe = pm2spipe_map[pm]; 760 if (spipe >= 0 && spipe < TD3_NUM_SPIPE) { 761 spipe_bw[spipe] += pmlist[pm].pm_bw; 762 spipe_pm_cnt[spipe]++; 763 } 764 } 765 766 /* step2-3: sort pmlist by decreasing pm_max_speed (insert sort) */ 767 for (i = 0; i < TD3_NUM_PHY_PM; i++) { 768 spd_max = 0; 769 idx_src = i; 770 idx_dst = i; 771 for (j = i; j < TD3_NUM_PHY_PM; j++) { 772 if (pmlist[j].pm_en && spd_max < pmlist[j].pm_max_spd) { 773 spd_max = pmlist[j].pm_max_spd; 774 idx_src = j; 775 } 776 } 777 if (idx_src != idx_dst) tdm_td3_ovsb_swap_pm(_tdm, pmlist, 778 idx_src, idx_dst); 779 if (idx_src == idx_dst && !pmlist[idx_src].pm_en) break; 780 } 781 782 /* step2-4: partition PMs into subpipes */ 783 for (pm_idx = 0; pm_idx < TD3_NUM_PHY_PM; pm_idx++) { 784 if (!pmlist[pm_idx].pm_en) break; 785 pm = pmlist[pm_idx].pm_num; 786 if (!(pm >=0 && pm < TD3_NUM_PM_MOD)) continue; 787 if (pm2spipe_map[pm] != -1) continue; 788 /* apply worst-fit to partition PM into a subpipe */ 789 dst_spipe = -1; 790 dst_spipe_bw = 0; 791 for (spipe = 0; spipe < TD3_NUM_SPIPE; spipe++) { 792 if (spipe_pm_cnt[spipe] < pms_per_spipe) { 793 if (dst_spipe == -1 || spipe_bw[spipe] < dst_spipe_bw) { 794 dst_spipe = spipe; 795 dst_spipe_bw= spipe_bw[spipe]; 796 } 797 } 798 } 799 if (dst_spipe != -1) { 800 spipe_bw[dst_spipe] += pmlist[pm_idx].pm_bw; 801 pm2spipe_map[pm] = dst_spipe; 802 TDM_PRINT2("TDM: partition PM %2d to subpipe %0d\n", 803 pm, dst_spipe); 804 } else { 805 result = FAIL; 806 TDM_ERROR1("Failed to map PM %0d to ovsb subpipe\n", pm); 807 } 808 } 809 TDM_SML_BAR 810 811 return result; 812 } 813 814 /** 815 @name: tdm_td3_ovsb_gen_pm2spipe_map 816 @param: 817 -- mapping_mode: 0->static, 1->dynamic. 818 */ 819 int 820 tdm_td3_ovsb_gen_pm2spipe_map(tdm_mod_t *_tdm, int mapping_mode) 821 { 822 if (mapping_mode == 0) { 823 /* static mapping */ 824 return (tdm_td3_ovsb_gen_pm2spipe_map_static(_tdm)); 825 } else { 826 /* dynamic mapping */ 827 return (tdm_td3_ovsb_gen_pm2spipe_map_dynamic(_tdm)); 828 } 829 } 830 831 /** 832 @name: tdm_td3_ovsb_add_prt_to_grp 833 @param: 834 835 Add port into given ovsb speed group. 836 If success, return pos of port in given speed group, otherwise return -1. 837 */ 838 int 839 tdm_td3_ovsb_add_prt_to_grp(tdm_mod_t *_tdm, int port_token, int grp) 840 { 841 int pos; 842 tdm_calendar_t *cal; 843 int param_token_empty; 844 845 param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports; 846 847 /* get pipe calendar */ 848 cal = tdm_td3_cmn_get_pipe_cal(_tdm); 849 if (cal == NULL) return (-1); 850 851 if (grp >= 0 && grp < cal->grp_num) { 852 for (pos = 0; pos < cal->grp_len; pos++) { 853 if (cal->cal_grp[grp][pos] == param_token_empty) { 854 cal->cal_grp[grp][pos] = port_token; 855 return pos; 856 } 857 } 858 } 859 860 return (-1); 861 } 862 863 /** 864 @name: tdm_td3_ovsb_migrate_prt 865 @param: 866 867 Migrate all allocated same-speed sister ports of the given port from 868 current ovsb grp to an appropriate grp. 869 */ 870 int 871 tdm_td3_ovsb_migrate_prt(tdm_mod_t *_tdm, int port_token, int slot_req) 872 { 873 int prt_buff[TD3_NUM_PM_LNS]; 874 int port_pm, port_spd; 875 int prt, prt_sp, prt_cnt, prt_done; 876 int grp, grp_lo, grp_hi, dst_grp, dst_pos, prev_grp, prev_pos; 877 int pos; 878 tdm_calendar_t *cal = NULL, *cal_prev = NULL; 879 int param_token_empty; 880 881 param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports; 882 for (prt_cnt = 0; prt_cnt < TD3_NUM_PM_LNS; prt_cnt++) { 883 prt_buff[prt_cnt] = param_token_empty; 884 } 885 886 /* get pipe calendar */ 887 cal = tdm_td3_cmn_get_pipe_cal(_tdm); 888 cal_prev = tdm_td3_cmn_get_pipe_cal_prev(_tdm); 889 if (cal == NULL || cal_prev == NULL) return (-1); 890 891 /* case 1: select group containing sister ports with the same speed */ 892 port_pm = tdm_td3_cmn_get_port_pm(_tdm, port_token); 893 port_spd = tdm_td3_cmn_get_port_speed_eth(_tdm, port_token); 894 prt_sp = tdm_td3_ovsb_get_prt_spipe(_tdm, port_token); 895 tdm_td3_ovsb_get_spipe_grp_range(_tdm, prt_sp, &grp_lo, &grp_hi); 896 897 /* move same-speed sister ports to prt_buff[] */ 898 prt_cnt = 0; 899 for (grp = grp_lo; grp <= grp_hi; grp++) { 900 if (tdm_td3_ovsb_get_grp_spd(_tdm, grp) != port_spd) continue; 901 for (pos = 0; pos < cal->grp_len; pos++) { 902 prt = cal->cal_grp[grp][pos]; 903 if (prt != param_token_empty) { 904 if (tdm_td3_cmn_get_port_pm(_tdm, prt) == port_pm) { 905 if (prt_cnt < TD3_NUM_PM_LNS) { 906 prt_buff[prt_cnt] = prt; 907 cal->cal_grp[grp][pos] = param_token_empty; 908 prt_cnt++; 909 TDM_PRINT3("%s, prt %0d, src_grp %0d\n", 910 "TDM: [a] move port from group to buffer", 911 prt, grp); 912 } 913 } 914 } 915 } 916 } 917 918 /* select a group which can accomodate all same-speed sister ports */ 919 dst_grp = tdm_td3_ovsb_sel_grp_4_prt(_tdm, port_token); 920 if (dst_grp == -1) return (-1); 921 922 /* move all ports in prt_buff[] to the selected group */ 923 if (dst_grp >= grp_lo && dst_grp <= grp_hi ) { 924 for (prt_cnt = 0; prt_cnt < TD3_NUM_PM_LNS; prt_cnt++) { 925 prt = prt_buff[prt_cnt]; 926 prev_grp = -1; 927 prev_pos = -1; 928 dst_pos = -1; 929 if (prt == param_token_empty) continue; 930 /* determine port's grp and pos before flexing */ 931 prt_done = BOOL_FALSE; 932 for (grp = grp_lo; grp <= grp_hi; grp++) { 933 for (pos = 0; pos < cal_prev->grp_len; pos++) { 934 if (cal_prev->cal_grp[grp][pos] == prt) { 935 prev_grp = grp; 936 prev_pos = pos; 937 prt_done = BOOL_TRUE; 938 break; 939 } 940 } 941 if (prt_done == BOOL_TRUE) break; 942 } 943 /* determine port's pos in dst_grp in current calendar */ 944 prt_done = BOOL_FALSE; 945 if (dst_grp == prev_grp && 946 prev_pos >= 0 && prev_pos < cal->grp_len) { 947 if (cal->cal_grp[dst_grp][prev_pos] == param_token_empty) { 948 dst_pos = prev_pos; 949 prt_done = BOOL_TRUE; 950 } else { 951 TDM_WARN4("%s, prt %0d, grp_prev %0d, pos_prev %0d\n", 952 "OVSB speed group violation on flex", 953 prt, prev_grp, prev_pos); 954 } 955 } 956 if (prt_done == BOOL_FALSE) { 957 for (pos = 0; pos < cal->grp_len; pos++) { 958 if (cal->cal_grp[dst_grp][pos] == param_token_empty) { 959 dst_pos = pos; 960 prt_done = BOOL_TRUE; 961 break; 962 } 963 } 964 } 965 /* migrate port to cal_grp[dst_grp][dst_pos] */ 966 if (prt_done == BOOL_TRUE && 967 dst_pos >= 0 && dst_pos < cal->grp_len) { 968 cal->cal_grp[dst_grp][dst_pos] = prt; 969 TDM_PRINT4("%s, prt %0d, dst_grp %0d, dst_pos %0d\n", 970 "TDM: [b] move port from buffer to group", 971 prt, dst_grp, dst_pos); 972 } 973 } 974 } 975 976 return dst_grp; 977 } 978 979 /** 980 @name: tdm_td3_ovsb_sel_grp_4_prt 981 @param: 982 983 Select an ovsb group to accommodate given port. 984 Return group index if found, otherwise return -1. 985 */ 986 int 987 tdm_td3_ovsb_sel_grp_4_prt(tdm_mod_t *_tdm, int port_token) 988 { 989 int port_pm, port_spd; 990 int prt, prt_pm, prt_spd, prt_sp, prt_done, prt_lo = 0, prt_hi = 0; 991 int pos, grp, grp_lo, grp_hi, grp_num, grp_spd; 992 int slot_req, slot_avail, slot_alloc; 993 tdm_calendar_t *cal; 994 int param_token_empty; 995 996 param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports; 997 998 /* get pipe calendar */ 999 cal = tdm_td3_cmn_get_pipe_cal(_tdm); 1000 if (cal == NULL) return (-1); 1001 1002 /* get range of ovsb groups for the given port */ 1003 prt_sp = tdm_td3_ovsb_get_prt_spipe(_tdm, port_token); 1004 tdm_td3_ovsb_get_spipe_grp_range(_tdm, prt_sp, &grp_lo, &grp_hi); 1005 1006 /* count number of ports with the same speed of given port within 1007 the same PM */ 1008 slot_req = 0; 1009 port_pm = tdm_td3_cmn_get_port_pm(_tdm, port_token); 1010 port_spd = tdm_td3_cmn_get_port_speed_eth(_tdm, port_token); 1011 tdm_td3_cmn_get_pipe_port_lo_hi(_tdm, &prt_lo, &prt_hi); 1012 for (prt = prt_lo; prt <= prt_hi; prt++) { 1013 if ((tdm_td3_cmn_get_port_speed(_tdm, prt) > 0) && 1014 (BOOL_TRUE == tdm_td3_cmn_chk_port_is_os(_tdm, prt))) { 1015 prt_pm = tdm_td3_cmn_get_port_pm(_tdm, prt); 1016 if (prt_pm == port_pm) { 1017 prt_spd = tdm_td3_cmn_get_port_speed_eth(_tdm, prt); 1018 if (prt_spd == port_spd) slot_req++; 1019 } 1020 } 1021 } 1022 if (!(slot_req > 0)) return (-1); 1023 1024 /* case 1: select group containing sister ports with the same speed */ 1025 grp_num = -1; 1026 prt_done = BOOL_FALSE; 1027 for (grp = grp_lo; grp <= grp_hi; grp++) { 1028 slot_alloc = 0; 1029 grp_spd = tdm_td3_ovsb_get_grp_spd(_tdm, grp); 1030 if (grp_spd != port_spd) continue; 1031 /* check if current group contains sister ports */ 1032 for (pos = 0; pos < cal->grp_len; pos++) { 1033 prt = cal->cal_grp[grp][pos]; 1034 if (prt != param_token_empty) { 1035 prt_pm = tdm_td3_cmn_get_port_pm(_tdm, prt); 1036 if (prt_pm == port_pm) { 1037 grp_num = grp; 1038 prt_done = BOOL_TRUE; 1039 slot_alloc++; 1040 if (prt == port_token) { 1041 grp_num = -1; 1042 break; 1043 } 1044 } 1045 } 1046 } 1047 /* check available resource in selected group */ 1048 if (prt_done == BOOL_TRUE) { 1049 if (grp_num != -1) { 1050 slot_avail = tdm_td3_ovsb_get_grp_empty_cnt(_tdm, grp_num); 1051 if (!(slot_avail >= (slot_req - slot_alloc))) { 1052 grp_num = tdm_td3_ovsb_migrate_prt(_tdm, port_token, 1053 slot_req); 1054 } 1055 } 1056 break; 1057 } 1058 } 1059 if (prt_done == BOOL_TRUE) return grp_num; 1060 1061 /* case 2: select group containing same speed ports */ 1062 grp_num = -1; 1063 prt_done = BOOL_FALSE; 1064 for (grp = grp_lo; grp <= grp_hi; grp++) { 1065 /* find same speed group, and check available resource */ 1066 grp_spd = tdm_td3_ovsb_get_grp_spd(_tdm, grp); 1067 if (grp_spd == port_spd) { 1068 slot_avail = tdm_td3_ovsb_get_grp_empty_cnt(_tdm, grp); 1069 if (slot_avail >= slot_req) { 1070 grp_num = grp; 1071 prt_done = BOOL_TRUE; 1072 break; 1073 } 1074 } 1075 } 1076 if (prt_done == BOOL_TRUE) return grp_num; 1077 1078 /* case 3: select group containing no ports (empty group) */ 1079 grp_num = -1; 1080 prt_done = BOOL_FALSE; 1081 for (grp = grp_lo; grp <= grp_hi; grp++) { 1082 slot_avail = tdm_td3_ovsb_get_grp_empty_cnt(_tdm, grp); 1083 if (slot_avail == cal->grp_len) { 1084 grp_num = grp; 1085 prt_done = BOOL_TRUE; 1086 break; 1087 } 1088 } 1089 if (prt_done == BOOL_TRUE) return grp_num; 1090 1091 return (-1); 1092 } 1093 1094 /** 1095 @name: tdm_td3_ovsb_fill_os_grps 1096 @param: 1097 */ 1098 int 1099 tdm_td3_ovsb_fill_os_grps(tdm_mod_t *_tdm) 1100 { 1101 int prt, prt_idx, pos, spd_idx, spd, grp, result = PASS; 1102 m_tdm_pipe_info_t *pipe_info; 1103 1104 /* iterate each speed class */ 1105 pipe_info = &(_tdm->_core_data.vars_pkg.pipe_info); 1106 for (spd_idx = 0; spd_idx < MAX_SPEED_TYPES; spd_idx++) { 1107 if (!pipe_info->os_spd_en[spd_idx]) continue; 1108 /* fill all ports in current speed class into ovsb group */ 1109 for (prt_idx=0; prt_idx<pipe_info->os_prt_cnt[spd_idx]; prt_idx++) { 1110 prt = pipe_info->os_prt[spd_idx][prt_idx]; 1111 spd = tdm_td3_cmn_get_port_speed(_tdm, prt); 1112 grp = tdm_td3_ovsb_sel_grp_4_prt(_tdm, prt); 1113 pos = tdm_td3_ovsb_add_prt_to_grp(_tdm, prt, grp); 1114 if (grp >= 0 && pos >= 0) { 1115 TDM_PRINT5("%s, spd %0dG, prt %3d, grp %2d, pos %0d\n", 1116 "TDM: add port to ovsb group", 1117 (spd / 1000), prt, grp, pos); 1118 } else { 1119 result = FAIL; 1120 TDM_ERROR5("%s, spd %0dG, prt %3d, grp %0d, pos %0d\n", 1121 "TDM: failed to add port to ovsb group", 1122 (spd / 1000), prt, grp, pos); 1123 } 1124 } 1125 } 1126 TDM_SML_BAR 1127 1128 return result; 1129 } 1130 1131 /** 1132 @name: tdm_td3_ovsb_consolidate_spipe 1133 @param: 1134 1135 Minimize the number of oversub speed groups of the given subpipe. 1136 Note: All ports belonging to the same subpipe should be considered. 1137 */ 1138 int 1139 tdm_td3_ovsb_consolidate_spipe(tdm_mod_t *_tdm, int spipe) 1140 { 1141 int grp_lo, grp_hi, grp_dst, grp_src, grp_spd_dst, grp_spd_src, 1142 grp_size_dst, grp_size_src, idx_dst, idx_src, prt_src; 1143 int param_token_empty; 1144 tdm_calendar_t *cal; 1145 1146 param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports; 1147 1148 cal = tdm_td3_cmn_get_pipe_cal(_tdm); 1149 if (cal == NULL) return PASS; 1150 1151 TDM_PRINT0("TDM: [FLEX] run consolidation\n"); 1152 tdm_td3_ovsb_get_spipe_grp_range(_tdm, spipe, &grp_lo, &grp_hi); 1153 for (grp_dst = grp_lo; grp_dst < grp_hi; grp_dst++) { 1154 grp_spd_dst = tdm_td3_ovsb_get_grp_spd(_tdm, grp_dst); 1155 grp_size_dst= tdm_td3_ovsb_get_grp_prt_cnt(_tdm, grp_dst); 1156 /* for each non-empty group, do consolidation */ 1157 if(grp_spd_dst == 0 || grp_size_dst == cal->grp_len) continue; 1158 for (grp_src = grp_dst + 1; grp_src <= grp_hi; grp_src++) { 1159 /* find two same speed groups */ 1160 grp_spd_src = tdm_td3_ovsb_get_grp_spd(_tdm, grp_src); 1161 grp_size_src= tdm_td3_ovsb_get_grp_prt_cnt(_tdm, grp_src); 1162 if (grp_spd_src != grp_spd_dst) continue; 1163 if ((grp_size_src + grp_size_dst) > cal->grp_len) continue; 1164 /* merge two same speed groups into one */ 1165 idx_dst = 0; 1166 for (idx_src = 0; idx_src < cal->grp_len; idx_src++) { 1167 prt_src = cal->cal_grp[grp_src][idx_src]; 1168 if(prt_src == param_token_empty) continue; 1169 while (idx_dst < cal->grp_len) { 1170 if (cal->cal_grp[grp_dst][idx_dst] == param_token_empty) { 1171 cal->cal_grp[grp_dst][idx_dst] = prt_src; 1172 cal->cal_grp[grp_src][idx_src] = param_token_empty; 1173 break; 1174 } 1175 idx_dst++; 1176 } 1177 } 1178 } 1179 } 1180 1181 return PASS; 1182 } 1183 1184 /** 1185 @name: tdm_td3_ovsb_flex_port_dn 1186 @param: 1187 1188 Remove down ports from ovsb speed groups 1189 */ 1190 int 1191 tdm_td3_ovsb_flex_port_dn(tdm_mod_t *_tdm) 1192 { 1193 int pos, prt, prt_done, prt_lo = 0, prt_hi = 0; 1194 int grp, flex_dn_exist = BOOL_FALSE; 1195 int param_token_empty; 1196 enum port_speed_e *param_speeds_prev; 1197 enum port_state_e *param_states_prev; 1198 tdm_calendar_t *cal; 1199 1200 param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports; 1201 param_speeds_prev = _tdm->_prev_chip_data.soc_pkg.speed; 1202 param_states_prev = _tdm->_prev_chip_data.soc_pkg.state; 1203 1204 /* check whether exists down port in current pipe */ 1205 tdm_td3_cmn_get_pipe_port_lo_hi(_tdm, &prt_lo, &prt_hi); 1206 for (prt = prt_lo; prt <= prt_hi; prt++) { 1207 if (param_states_prev[prt - 1] == PORT_STATE__FLEX_OVERSUB_DN || 1208 param_states_prev[prt - 1] == PORT_STATE__FLEX_OVERSUB_CH) { 1209 flex_dn_exist = BOOL_TRUE; 1210 break; 1211 } 1212 } 1213 if (flex_dn_exist == BOOL_FALSE) return PASS; 1214 1215 TDM_PRINT0("TDM: Flex DOWN ports\n"); 1216 /* remove down_ports and spd_changed_ports */ 1217 cal = tdm_td3_cmn_get_pipe_cal(_tdm); 1218 if (cal == NULL) return PASS; 1219 for (prt = prt_lo; prt <= prt_hi; prt++) { 1220 if (param_states_prev[prt-1] == PORT_STATE__FLEX_OVERSUB_DN || 1221 param_states_prev[prt-1] == PORT_STATE__FLEX_OVERSUB_CH) { 1222 prt_done = BOOL_FALSE; 1223 for (grp = 0; grp <= cal->grp_num; grp++) { 1224 for (pos = 0; pos < cal->grp_len; pos++) { 1225 if (cal->cal_grp[grp][pos] == prt) { 1226 cal->cal_grp[grp][pos] = param_token_empty; 1227 prt_done = BOOL_TRUE; 1228 TDM_PRINT5("%s %0d, spd %0dG, grp %0d, pos %0d\n", 1229 "TDM: [FLEX DN] remove down port", 1230 prt, param_speeds_prev[prt]/1000, 1231 grp, pos); 1232 break; 1233 } 1234 } 1235 if (prt_done == BOOL_TRUE) break; 1236 } 1237 } 1238 } 1239 TDM_SML_BAR 1240 1241 return PASS; 1242 } 1243 1244 /** 1245 @name: tdm_td3_ovsb_flex_port_up 1246 @param: 1247 1248 Add up ports into ovsb speed groups 1249 */ 1250 int 1251 tdm_td3_ovsb_flex_port_up(tdm_mod_t *_tdm) 1252 { 1253 int prt_lo, prt_hi, prt, prt_spd, pos, grp, spipe, result = PASS; 1254 int spipe_done[TD3_NUM_SPIPE]; 1255 int flex_up_exist = BOOL_FALSE; 1256 enum port_state_e *param_states_prev; 1257 1258 param_states_prev = _tdm->_prev_chip_data.soc_pkg.state; 1259 for (spipe = 0; spipe < TD3_NUM_SPIPE; spipe++) spipe_done[spipe] = 0; 1260 tdm_td3_cmn_get_pipe_port_lo_hi(_tdm, &prt_lo, &prt_hi); 1261 1262 /* check whether exists up port in current pipe */ 1263 for (prt = prt_lo; prt <= prt_hi; prt++) { 1264 if (param_states_prev[prt - 1] == PORT_STATE__FLEX_OVERSUB_UP || 1265 param_states_prev[prt - 1] == PORT_STATE__FLEX_OVERSUB_CH) { 1266 flex_up_exist = BOOL_TRUE; 1267 break; 1268 } 1269 } 1270 if (flex_up_exist == BOOL_FALSE) return result; 1271 TDM_PRINT0("TDM: Flex UP ports\n"); 1272 1273 /* do consolidation */ 1274 1275 for (prt = prt_lo; prt <= prt_hi; prt++) { 1276 if (param_states_prev[prt - 1] == PORT_STATE__FLEX_OVERSUB_UP || 1277 param_states_prev[prt - 1] == PORT_STATE__FLEX_OVERSUB_CH) { 1278 spipe = tdm_td3_ovsb_get_prt_spipe(_tdm, prt); 1279 if (spipe >= 0 && spipe < TD3_NUM_SPIPE) { 1280 if (spipe_done[spipe] == 0) { 1281 tdm_td3_ovsb_consolidate_spipe(_tdm, spipe); 1282 spipe_done[spipe] = 1; 1283 } 1284 } 1285 } 1286 } 1287 1288 /* add up_ports and spd_changed_ports */ 1289 for (prt = prt_lo; prt <= prt_hi; prt++) { 1290 if (param_states_prev[prt - 1] == PORT_STATE__FLEX_OVERSUB_UP || 1291 param_states_prev[prt - 1] == PORT_STATE__FLEX_OVERSUB_CH) { 1292 prt_spd = tdm_td3_cmn_get_port_speed(_tdm, prt); 1293 grp = tdm_td3_ovsb_sel_grp_4_prt(_tdm, prt); 1294 pos = tdm_td3_ovsb_add_prt_to_grp(_tdm, prt, grp); 1295 if (grp != -1 && pos != -1) { 1296 TDM_PRINT5("%s, prt %0d, spd %0dG, grp %0d, pos %0d\n", 1297 "TDM: [FLEX] add up_port", 1298 prt, (prt_spd / 1000), grp, pos); 1299 } else { 1300 result = FAIL; 1301 TDM_ERROR3("%s, prt %0d, spd %0dG, no available ovsb speed group\n", 1302 "TDM: [FLEX] failed to add up_port", 1303 prt, (prt_spd / 1000)); 1304 } 1305 } 1306 } 1307 TDM_SML_BAR 1308 1309 return result; 1310 } 1311 1312 /** 1313 @name: tdm_td3_ovsb_gen_os_grps_init 1314 @param: 1315 */ 1316 int 1317 tdm_td3_ovsb_gen_os_grps_init(tdm_mod_t *_tdm) 1318 { 1319 int result = PASS; 1320 1321 /* partition PMs into subpipes */ 1322 if (tdm_td3_ovsb_gen_pm2spipe_map(_tdm, 0) != PASS) result = FAIL; 1323 1324 /* allocate ports into ovsb groups based on partitioned subpipes */ 1325 if (tdm_td3_ovsb_fill_os_grps(_tdm) != PASS) result = FAIL; 1326 1327 return result; 1328 } 1329 1330 /** 1331 @name: tdm_td3_ovsb_gen_os_grps_flex 1332 @param: 1333 */ 1334 int 1335 tdm_td3_ovsb_gen_os_grps_flex(tdm_mod_t *_tdm) 1336 { 1337 int grp, pos, result = PASS; 1338 tdm_calendar_t *cal = NULL, *cal_prev = NULL; 1339 1340 /* step 1: copy ovsb grps from cal_prev into cal */ 1341 TDM_PRINT0("TDM: Restore ovsb grps by pre_flex values\n"); 1342 cal = tdm_td3_cmn_get_pipe_cal(_tdm); 1343 cal_prev = tdm_td3_cmn_get_pipe_cal_prev(_tdm); 1344 if (cal == NULL || cal_prev == NULL) return FAIL; 1345 for (grp = 0; grp < cal->grp_num; grp++) { 1346 for (pos=0; pos<cal->grp_len; pos++) { 1347 cal->cal_grp[grp][pos] = cal_prev->cal_grp[grp][pos]; 1348 } 1349 } 1350 1351 /* step 2: partition PMs into subpipes */ 1352 if (tdm_td3_ovsb_gen_pm2spipe_map(_tdm, 0) != PASS) result = FAIL; 1353 1354 /* step 3: flex up-ports */ 1355 if (tdm_td3_ovsb_flex_port_dn(_tdm) != PASS) result = FAIL; 1356 1357 /* step 4: flex down-ports */ 1358 if (tdm_td3_ovsb_flex_port_up(_tdm) != PASS) result = FAIL; 1359 1360 return result; 1361 } 1362 1363 /** 1364 @name: tdm_td3_ovsb_gen_os_grps 1365 @param: 1366 */ 1367 int 1368 tdm_td3_ovsb_gen_os_grps(tdm_mod_t *_tdm) 1369 { 1370 if (_tdm->_chip_data.soc_pkg.flex_port_en == 1) { 1371 return (tdm_td3_ovsb_gen_os_grps_flex(_tdm)); 1372 } else { 1373 return (tdm_td3_ovsb_gen_os_grps_init(_tdm)); 1374 } 1375 } 1376 1377 /** 1378 @name: tdm_td3_ovsb_gen_pkt_shaper_per_prt 1379 @param: 1380 1381 Populates Pkt shaper calendar - per port 1382 */ 1383 int 1384 tdm_td3_ovsb_gen_pkt_shaper_per_prt(tdm_mod_t *_tdm, int prt) 1385 { 1386 int i, pos, prt_slots, prt_pm, prt_spipe, slot_cnt, result = PASS; 1387 int pm_shaper_tbl[TD3_SHAPER_NUM_PM_SLOTS]; 1388 int *pkt_shaper_cal, *pm2spipe_map; 1389 int param_token_empty; 1390 1391 param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports; 1392 pm2spipe_map = _tdm->_chip_data.soc_pkg.soc_vars.td3.pm_ovs_halfpipe; 1393 1394 for (i = 0; i < TD3_SHAPER_NUM_PM_SLOTS; i++) 1395 pm_shaper_tbl[i] = param_token_empty; 1396 1397 /* generate pm shaper calendar for the current port */ 1398 prt_slots = tdm_td3_cmn_get_port_speed_eth(_tdm, prt) / 1399 TD3_SHAPER_SLOT_UNIT; 1400 for (slot_cnt = 0; slot_cnt < prt_slots; slot_cnt++) { 1401 pos = tdm_td3_ovsb_get_pm_shaper_prt_pos(_tdm, prt, slot_cnt) % 1402 TD3_SHAPER_NUM_PM_SLOTS; 1403 pm_shaper_tbl[pos] = prt; 1404 } 1405 1406 TDM_PRINT1("TDM: prt %3d, pm_shaper_cal[", prt); 1407 for (pos = 0; pos < TD3_SHAPER_NUM_PM_SLOTS; pos++) { 1408 TDM_PRINT2("%0d:%0d, ", pos, pm_shaper_tbl[pos]); 1409 } 1410 TDM_PRINT0("]\n"); 1411 1412 /* Get the right pkt scheduler calendar*/ 1413 prt_pm = tdm_td3_cmn_get_port_pm(_tdm, prt); 1414 prt_spipe = pm2spipe_map[prt_pm]; 1415 pkt_shaper_cal = tdm_td3_ovsb_get_pkt_shaper_cal(_tdm, prt_spipe); 1416 if (pkt_shaper_cal == NULL) return FAIL; 1417 1418 /* Populate pkt scheduler calendar */ 1419 slot_cnt = 0; 1420 for (i = 0; i < TD3_SHAPER_NUM_PM_SLOTS; i++) { 1421 if (pm_shaper_tbl[i] != param_token_empty) { 1422 pos = tdm_td3_ovsb_get_pkt_shaper_prt_pos(_tdm, prt, i); 1423 slot_cnt++; 1424 if (pos >=0 && pos < TD3_SHAPING_GRP_LEN) { 1425 pkt_shaper_cal[pos] = pm_shaper_tbl[i]; 1426 TDM_PRINT4("%s, prt %3d, slot_cnt %0d, index %0d\n", 1427 "TDM: [pkt_shaper_cal]", 1428 pm_shaper_tbl[i], slot_cnt, pos); 1429 } else { 1430 result = FAIL; 1431 TDM_ERROR3("%s, prt %3d, slot_cnt %0d\n", 1432 "[pkt_shaper_cal] Failed to allocate port slots", 1433 prt, slot_cnt); 1434 } 1435 } 1436 } 1437 1438 return result; 1439 } 1440 1441 /** 1442 @name: tdm_td3_ovsb_gen_pkt_shaper_init 1443 @param: 1444 1445 Populates Pkt shaper calendar 1446 */ 1447 int 1448 tdm_td3_ovsb_gen_pkt_shaper_init(tdm_mod_t *_tdm) 1449 { 1450 int spipe, grp, grp_lo, grp_hi, pos, prt; 1451 tdm_calendar_t *cal; 1452 int param_token_empty; 1453 1454 param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports; 1455 cal = tdm_td3_cmn_get_pipe_cal(_tdm); 1456 if (cal == NULL) return FAIL; 1457 1458 for (spipe = 0; spipe < TD3_NUM_SPIPE; spipe++) { 1459 tdm_td3_ovsb_get_spipe_grp_range(_tdm, spipe, &grp_lo, &grp_hi); 1460 for (grp = grp_lo; grp <= grp_hi; grp++) { 1461 for (pos = 0; pos < cal->grp_len; pos++) { 1462 prt = cal->cal_grp[grp][pos]; 1463 if (prt != param_token_empty) 1464 tdm_td3_ovsb_gen_pkt_shaper_per_prt(_tdm, prt); 1465 } 1466 } 1467 } 1468 TDM_SML_BAR 1469 1470 return PASS; 1471 } 1472 1473 /** 1474 @name: tdm_td3_ovsb_gen_pkt_shaper_flex 1475 @param: 1476 1477 Populates Pkt shaper calendar 1478 */ 1479 int 1480 tdm_td3_ovsb_gen_pkt_shaper_flex(tdm_mod_t *_tdm) 1481 { 1482 int i, spipe, grp, grp_lo, grp_hi, pos, prt; 1483 int port_done[TD3_NUM_EXT_PORTS]; 1484 tdm_calendar_t *cal; 1485 int *pkt_cal, *pkt_cal_prev; 1486 int param_token_empty; 1487 enum port_state_e *param_states_prev; 1488 1489 param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports; 1490 param_states_prev = _tdm->_prev_chip_data.soc_pkg.state; 1491 cal = tdm_td3_cmn_get_pipe_cal(_tdm); 1492 if (cal == NULL) return FAIL; 1493 for (i = 0; i < TD3_NUM_EXT_PORTS; i++) port_done[i] = 0; 1494 1495 /* step 1: copy pkt shaper calendar from pkt_cal_prev into pkt_cal */ 1496 for (spipe = 0; spipe < TD3_NUM_SPIPE; spipe++) { 1497 pkt_cal = tdm_td3_ovsb_get_pkt_shaper_cal(_tdm, spipe); 1498 pkt_cal_prev = tdm_td3_ovsb_get_pkt_shaper_cal_prev(_tdm, spipe); 1499 if (pkt_cal == NULL || pkt_cal_prev == NULL) continue; 1500 for (i = 0; i < TD3_SHAPING_GRP_LEN; i++) { 1501 prt = pkt_cal_prev[i]; 1502 if (param_states_prev[prt - 1] == PORT_STATE__FLEX_OVERSUB_DN || 1503 param_states_prev[prt - 1] == PORT_STATE__FLEX_OVERSUB_CH) { 1504 prt = param_token_empty; 1505 } 1506 pkt_cal[i] = prt; 1507 if (prt!=param_token_empty && prt>0 && prt<TD3_NUM_EXT_PORTS) { 1508 port_done[prt] = 1; 1509 } 1510 } 1511 } 1512 1513 /* step 2: allocate slots for up-ports in pkt shaper calendar */ 1514 for (spipe = 0; spipe < TD3_NUM_SPIPE; spipe++) { 1515 tdm_td3_ovsb_get_spipe_grp_range(_tdm, spipe, &grp_lo, &grp_hi); 1516 for (grp = grp_lo; grp <= grp_hi; grp++) { 1517 for (pos = 0; pos < cal->grp_len; pos++) { 1518 prt = cal->cal_grp[grp][pos]; 1519 if (prt != param_token_empty && 1520 prt > 0 && prt < TD3_NUM_EXT_PORTS) { 1521 if (port_done[prt] == 0) { 1522 tdm_td3_ovsb_gen_pkt_shaper_per_prt(_tdm, prt); 1523 port_done[prt] = 1; 1524 } 1525 } 1526 } 1527 } 1528 } 1529 TDM_SML_BAR 1530 1531 return PASS; 1532 } 1533 1534 /** 1535 @name: tdm_td3_ovsb_gen_pkt_shaper 1536 @param: 1537 1538 Populates Pkt shaper calendar 1539 */ 1540 int 1541 tdm_td3_ovsb_gen_pkt_shaper(tdm_mod_t *_tdm) 1542 { 1543 if (_tdm->_chip_data.soc_pkg.flex_port_en == 1) { 1544 return (tdm_td3_ovsb_gen_pkt_shaper_flex(_tdm)); 1545 /* return (tdm_td3_ovsb_gen_pkt_shaper_init(_tdm)); */ 1546 } else { 1547 return (tdm_td3_ovsb_gen_pkt_shaper_init(_tdm)); 1548 } 1549 1550 return PASS; 1551 } 1552 1553 /** 1554 @name: tdm_td3_ovsb_gen_pm2pblk_map 1555 @param: 1556 @desc: [chip_specific] 1557 1558 Maps PM num (block_id) to OVSB pblk id 1559 */ 1560 int 1561 tdm_td3_ovsb_gen_pm2pblk_map(tdm_mod_t *_tdm) 1562 { 1563 int pm, pm_lo, pm_hi, spipe; 1564 int pblk_idx[TD3_NUM_SPIPE]; 1565 int *pm2pblk_map = NULL, *pm2spipe_map = NULL; 1566 1567 pm2pblk_map = _tdm->_chip_data.soc_pkg.soc_vars.td3.pm_num_to_pblk; 1568 pm2spipe_map = _tdm->_chip_data.soc_pkg.soc_vars.td3.pm_ovs_halfpipe; 1569 tdm_td3_cmn_get_pipe_pm_lo_hi(_tdm, &pm_lo, &pm_hi); 1570 for (spipe = 0; spipe < TD3_NUM_SPIPE; spipe++) pblk_idx[spipe] = 0; 1571 1572 for (pm = pm_lo; pm <= pm_hi && pm < TD3_NUM_PM_MOD; pm++) { 1573 pm2pblk_map[pm] = -1; 1574 spipe = pm2spipe_map[pm]; 1575 if (spipe >= 0 && spipe < TD3_NUM_SPIPE) { 1576 /* [chip_specific] halpipe 0 uses increment order: [0,1,...7] 1577 * halpipe 1 uses decrement order: [7,6,...0] 1578 */ 1579 if (spipe == 0) { 1580 pm2pblk_map[pm] = pblk_idx[spipe]; 1581 } else { 1582 pm2pblk_map[pm] = TD3_NUM_PMS_PER_SPIPE - pblk_idx[spipe] - 1; 1583 } 1584 pblk_idx[spipe]++; 1585 TDM_PRINT3("TDM: map pm %2d to subpipe %0d pblk %0d\n", 1586 pm, spipe, pm2pblk_map[pm]); 1587 } 1588 } 1589 TDM_SML_BAR 1590 1591 return PASS; 1592 } 1593 1594 /** 1595 @name: tdm_td3_vbs_scheduler_ovs_2 1596 @param: 1597 */ 1598 int 1599 tdm_td3_vbs_scheduler_ovs(tdm_mod_t *_tdm) 1600 { 1601 int result = PASS; 1602 int param_cal_id = _tdm->_core_data.vars_pkg.cal_id; 1603 1604 /* generate ovsb groups */ 1605 TDM_PRINT1("Generating OVSB groups for PIPE %0d\n\n", param_cal_id); 1606 if (tdm_td3_ovsb_gen_os_grps(_tdm) != PASS) result = FAIL; 1607 1608 /* generate PKT scheduler */ 1609 TDM_PRINT1("Generating OVSB PKT Scheduler for PIPE %0d\n\n", param_cal_id); 1610 /* if (tdm_td3_ovsb_pkt_shaper_new(_tdm) != PASS) result = FAIL; */ 1611 if (tdm_td3_ovsb_gen_pkt_shaper(_tdm) != PASS) result = FAIL; 1612 1613 /* generate PM_NUM to PBLK mapping */ 1614 TDM_PRINT1("Generating OVSB PM2PBLK mapping for PIPE %0d\n\n", param_cal_id); 1615 if(tdm_td3_ovsb_gen_pm2pblk_map(_tdm) != PASS) result = FAIL; 1616 1617 return result; 1618 }