trident3_tdm.c (87116B)
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: trident3_tdm.c 8 * Purpose: 9 * Requires: 10 */ 11 12 13 #include <shared/bsl.h> 14 #include <soc/tdm/core/tdm_top.h> 15 16 #include <soc/defs.h> 17 #include <soc/mem.h> 18 19 #if defined(BCM_TRIDENT3_SUPPORT) 20 #include <soc/trident3.h> 21 #include <soc/trident3_tdm.h> 22 #include <soc/tdm/trident3/tdm_td3_defines.h> 23 24 25 /*** START SDK API COMMON CODE ***/ 26 27 /*! @fn void _soc_td3_tdm_print_port_map( 28 int unit, 29 soc_port_map_type_t *port_map) 30 @param unit Chip unit number. 31 @param port_map Pointer to a soc_port_map_type_t struct variable. 32 @brief Debug API to print soc_port_map_type_t 33 */ 34 void 35 _soc_td3_tdm_print_port_map(int unit, soc_port_map_type_t *port_map) 36 { 37 int port; 38 int is_hg2, is_ovs, is_mgm; 39 int speed, phy_port, idb_port, mmu_port, num_lanes, pblk; 40 int phy_bmap, p2l_map, m2p_map; 41 42 for (port = 0; port < SOC_MAX_NUM_PORTS; port++) { 43 is_mgm = SOC_PBMP_MEMBER(port_map->management_pbm, port) ? 1 : 0; 44 if ((is_mgm == 1) || (port_map->log_port_speed[port] > 0)) { 45 speed = is_mgm ? 10 : port_map->log_port_speed[port]/1000; 46 phy_port = port_map->port_l2p_mapping[port]; 47 idb_port = port_map->port_l2i_mapping[port]; 48 mmu_port = port_map->port_p2m_mapping[phy_port]; 49 num_lanes = port_map->port_num_lanes[port]; 50 pblk = port_map->port_p2PBLK_inst_mapping[phy_port]; 51 phy_bmap = SOC_PBMP_MEMBER(port_map->physical_pbm, phy_port) ? 1 : 0; 52 is_hg2 = SOC_PBMP_MEMBER(port_map->hg2_pbm, port) ? 1 : 0; 53 is_ovs = SOC_PBMP_MEMBER(port_map->oversub_pbm, port) ? 1 : 0; 54 p2l_map = port_map->port_p2l_mapping[phy_port]; 55 m2p_map = port_map->port_m2p_mapping[mmu_port]; 56 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 57 "log_port=%3d phy_port=%3d speed=%3dG " 58 "%s %s idb_port=%3d mmu_port=%3d " 59 "num_lanes=%1d pblk=%3d phy_bmap=%1d " 60 "p2l_map=%3d "), 61 port, phy_port, speed, 62 (is_hg2==1) ? "HG2" : "ETH", 63 (is_ovs==1) ? "OVS" : " LR", 64 idb_port, mmu_port, num_lanes, pblk, 65 phy_bmap, p2l_map)); 66 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "m2p_map=%3d %s\n"), 67 m2p_map, (is_mgm==1) ? "MGM" : "" )); 68 } 69 } 70 71 } 72 73 74 /*! @fn void _soc_td3_tdm_print_tdm_info( 75 int unit, 76 soc_tdm_schedule_t *tdm_info, 77 int hpipe, 78 int is_ing) 79 @param unit Chip unit number. 80 @param tdm_info Pointer to a soc_tdm_schedule_t struct variable. 81 @param hpipe Half Pipe. 82 @param is_ing distinguishes between IP and EP schedulers 83 @brief Debug API to print soc_tdm_schedule_t 84 */ 85 void 86 _soc_td3_tdm_print_tdm_info(int unit, soc_tdm_schedule_t *tdm_info, 87 int hpipe, int is_ing) 88 { 89 int cal_len, j, m; 90 91 if (hpipe == 0) { 92 for (cal_len = tdm_info->cal_len; cal_len > 0; cal_len--) { 93 if (tdm_info->linerate_schedule[cal_len - 1] != TD3_NUM_EXT_PORTS) { 94 break; 95 } 96 } 97 98 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 99 "\tMAIN CALENDAR: cal_len=%3d \n"), 100 cal_len )); 101 for (j=0; j < cal_len; j++) { 102 if (j%16==0) { 103 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 104 "\n %3d : %3d\t"), 105 j, j+15)); 106 } 107 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 108 "%5d"), 109 tdm_info->linerate_schedule[j])); 110 } 111 } 112 113 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 114 "\n\n\tOVS TABLES: HPIPE= %3d \n"), 115 hpipe )); 116 for (j=0; j< tdm_info->num_ovs_groups; j++) { 117 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 118 "\nOVS_CAL[%d]:\t"), 119 j )); 120 for (m=0; m< tdm_info->ovs_group_len; m++) { 121 if (tdm_info->oversub_schedule[j][m] != TD3_NUM_EXT_PORTS) { 122 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 123 "%d\t"), 124 tdm_info->oversub_schedule[j][m] )); 125 } else { 126 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 127 "---\t"))); 128 } 129 } 130 } 131 132 if (is_ing == 1) { 133 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 134 "\n\n\tPKT_SCHEDULER: HPIPE= %3d \n"), 135 hpipe )); 136 for (j=0; j<tdm_info->pkt_sch_or_ovs_space_len; j++) { 137 if (j%16==0) { 138 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 139 "\n %3d : %3d\t"), 140 j, j+15 )); 141 } 142 if (tdm_info->pkt_sch_or_ovs_space[0][j] != TD3_NUM_EXT_PORTS) { 143 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 144 "\t%d"), 145 tdm_info->pkt_sch_or_ovs_space[0][j] )); 146 } else { 147 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 148 "\t---"))); 149 } 150 } 151 } 152 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit,"\n"))); 153 } 154 155 156 /*! @fn void _soc_td3_tdm_print_port_resource( 157 int unit, 158 soc_port_resource_t *port_info, 159 int entry_num) 160 @param unit Chip unit number. 161 @param port_info Pointer to a soc_port_resource_t struct variable. 162 @param entry_num entry number. 163 @brief Debug API to print soc_port_resource_t 164 */ 165 void 166 _soc_td3_tdm_print_port_resource(int unit, 167 soc_port_resource_t *port_info, 168 int entry_num) 169 { 170 int is_hg2, lane; 171 172 is_hg2 = 0; 173 if (port_info->encap == _SHR_PORT_ENCAP_HIGIG2) { 174 is_hg2=1; 175 } 176 177 if (port_info->physical_port == -1) { 178 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 179 "nport=%3d DOWN: " 180 "logical_port=%3d physical_port=%3d\n"), 181 entry_num, port_info->logical_port, 182 port_info->physical_port)); 183 } else { 184 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 185 "nport=%3d UP : " 186 "logical_port=%3d physical_port=%3d mmu_port=%3d "), 187 entry_num, port_info->logical_port, 188 port_info->physical_port, 189 port_info->mmu_port )); 190 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 191 "idb_port=%3d pipe=%3d speed=%3d num_lanes=%1d " 192 "%s %s\n"), 193 port_info->idb_port, 194 port_info->pipe, port_info->speed/1000, 195 port_info->num_lanes, 196 (is_hg2==1) ? "HG2": "ETH", 197 (port_info->oversub==1) ? "OVS": " LR" )); 198 for (lane = 0; lane < SOC_PORT_RESOURCE_LANES_MAX; lane++) { 199 if (port_info->lane_info[lane] != NULL) { 200 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 201 "nport=%3d lane_info[%d]: pgw=%3d" 202 "xlp=%3d port_index=%3d\n"), 203 entry_num, lane, 204 port_info->lane_info[lane]->pgw, 205 port_info->lane_info[lane]->xlp, 206 port_info->lane_info[lane]->port_index)); 207 } 208 } 209 } 210 } 211 212 213 /*! @fn void _soc_td3_tdm_print_schedule_state( 214 int unit, 215 soc_port_schedule_state_t *sch_info) 216 @param unit Chip unit number. 217 @param sch_info Pointer to a soc_port_schedule_state_t struct variable. 218 @brief Debug API to print sch_info 219 */ 220 void 221 _soc_td3_tdm_print_schedule_state(int unit, 222 soc_port_schedule_state_t *sch_info) 223 { 224 int i, pipe, hpipe, print_tdm; 225 soc_tdm_schedule_t *tdm_schedule; 226 227 print_tdm = 1; 228 229 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 230 "\n\nPRINTING soc_port_schedule_state_t \n"))); 231 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 232 "nport= %3d\n"), 233 sch_info->nport)); 234 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 235 "frequency= %4dMHz\n"), 236 sch_info->frequency)); 237 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 238 "bandwidth= %4d\n"), 239 sch_info->bandwidth)); 240 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 241 "io_bandwidth= %4d\n"), 242 sch_info->io_bandwidth)); 243 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 244 "lossless= %1d\n"), 245 sch_info->lossless)); 246 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 247 "is_flexport= %1d\n"), 248 sch_info->is_flexport)); 249 250 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 251 "\nPRINTING soc_port_schedule_state_t" 252 "::[in_port_map]\n"))); 253 _soc_td3_tdm_print_port_map(unit, &sch_info->in_port_map); 254 255 if (sch_info->is_flexport == 1) { 256 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 257 "\nPRINTING soc_port_schedule_state_t" 258 "::[out_port_map]\n"))); 259 _soc_td3_tdm_print_port_map(unit, &sch_info->out_port_map); 260 } 261 262 if (print_tdm == 1) { 263 for (pipe = 0; pipe < NUM_PIPE(unit); pipe++) { 264 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 265 "\n====== TDM Tables PIPE=%1d INGRESS\n"), 266 pipe)); 267 for (hpipe = 0; hpipe< MAX_SCH_SLICES; hpipe++) { 268 tdm_schedule = &(sch_info->tdm_ingress_schedule_pipe[ 269 pipe].tdm_schedule_slice[hpipe]); 270 _soc_td3_tdm_print_tdm_info(unit, tdm_schedule, hpipe, 1); 271 } 272 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 273 "\n====== TDM Tables PIPE=%1d EGRESS\n"), 274 pipe)); 275 for (hpipe = 0; hpipe< MAX_SCH_SLICES; hpipe++) { 276 tdm_schedule = &(sch_info->tdm_egress_schedule_pipe[ 277 pipe].tdm_schedule_slice[hpipe]); 278 _soc_td3_tdm_print_tdm_info(unit, tdm_schedule, hpipe, 0); 279 } 280 } 281 } 282 283 if ((sch_info->is_flexport == 1) && (sch_info->nport > 0)) { 284 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 285 "\n====== FLEXPORT RESOURCES ===== " 286 "num entries= %d = \n"), 287 sch_info->nport)); 288 for (i = 0; i < sch_info->nport; i++) { 289 _soc_td3_tdm_print_port_resource(unit, &sch_info->resource[i], i); 290 } 291 } 292 } 293 294 295 /*! @fn void soc_td3_tdm_get_port_ratio( 296 int unit, 297 soc_port_schedule_state_t *sch_info, 298 int pm_num, 299 int *pm_mode, 300 int prev_or_new) 301 @param unit Chip unit number. 302 @param sch_info Pointer to a soc_port_schedule_state_t struct variable. 303 @param pm_num PM block_id (0 to 31) 304 @param *pm_mode mode to be returned. 305 @param prev_or_new function looks in in_port_map or out_port_map. 306 @brief Help function to get port ratio. 307 */ 308 309 /* 310 * #1 single: 100 - x - x - x SOC_TD3_PORT_RATIO_SINGLE 311 * #2 single: 40 - x - x - x SOC_TD3_PORT_RATIO_TRI_023_2_1_1 312 * #3 dual: 50 - x - 50 - x SOC_TD3_PORT_RATIO_DUAL_1_1 313 * #4 dual: 40 - x - 40 - x SOC_TD3_PORT_RATIO_DUAL_1_1 314 * #5 dual: 20 - x - 20 - x SOC_TD3_PORT_RATIO_DUAL_1_1 315 * #6 dual: 40 - x - 20 - x SOC_TD3_PORT_RATIO_DUAL_2_1 316 * #7 dual: 20 - x - 40 - x SOC_TD3_PORT_RATIO_DUAL_1_2 317 * #8 tri: 50 - x - 25/x - 25/x SOC_TD3_PORT_RATIO_TRI_023_2_1_1 318 * #9 tri: 20 - x - 10/x - 10/x SOC_TD3_PORT_RATIO_TRI_023_2_1_1 319 * #10 tri: 40 - x - 10/x - 10/x SOC_TD3_PORT_RATIO_TRI_023_4_1_1 320 * #11 tri: 25/x - 25/x - 50 - x SOC_TD3_PORT_RATIO_TRI_012_1_1_2 321 * #12 tri: 10/x - 10/x - 20 - x SOC_TD3_PORT_RATIO_TRI_012_1_1_2 322 * #13 tri: 10/x - 10/x - 40 - x SOC_TD3_PORT_RATIO_TRI_012_1_1_4 323 * #14 quad: 25/x - 25/x - 25/x - 25/x SOC_TD3_PORT_RATIO_QUAD 324 * #15 quad: 10/x - 10/x - 10/x - 10/x SOC_TD3_PORT_RATIO_QUAD 325 */ 326 void 327 soc_td3_tdm_get_port_ratio(int unit, 328 soc_port_schedule_state_t *sch_info, 329 int pm_num, int *pm_mode, int prev_or_new) 330 { 331 int port, phy_port_base, lane, mode = 0; 332 int num_lanes[TRIDENT3_TDM_PORTS_PER_PBLK]; 333 int speed_max[TRIDENT3_TDM_PORTS_PER_PBLK]; 334 soc_port_map_type_t *port_map; 335 int l_speed = 0, l_num_lanes = 0; 336 337 sal_memset(num_lanes, 0, TRIDENT3_TDM_PORTS_PER_PBLK*sizeof(int)); 338 sal_memset(speed_max, 0, TRIDENT3_TDM_PORTS_PER_PBLK*sizeof(int)); 339 340 if (prev_or_new == 1) { 341 port_map = &(sch_info->in_port_map); 342 } else { 343 port_map = &(sch_info->out_port_map); 344 } 345 346 phy_port_base = 1 + (pm_num * TRIDENT3_TDM_PORTS_PER_PBLK); 347 for (lane = 0; lane < TRIDENT3_TDM_PORTS_PER_PBLK; lane += 2) { 348 port = port_map->port_p2l_mapping[phy_port_base + lane]; 349 if ( (port == -1) || (port_map->log_port_speed[port]==0) ) { 350 num_lanes[lane] = -1; 351 speed_max[lane] = -1; 352 } else { 353 soc_td3_tdm_get_log_port_speed(unit, sch_info, port, 354 prev_or_new, &l_speed, &l_num_lanes); 355 num_lanes[lane] = l_num_lanes; 356 speed_max[lane] = l_speed; 357 } 358 } 359 360 if (num_lanes[0] == 4) { 361 mode = SOC_TD3_PORT_RATIO_SINGLE; 362 } else if (num_lanes[0] == 2 && num_lanes[2] == 2) { 363 if (speed_max[0] == speed_max[2]) { 364 mode = SOC_TD3_PORT_RATIO_DUAL_1_1; 365 } else if (speed_max[0] > speed_max[2]) { 366 mode = SOC_TD3_PORT_RATIO_DUAL_2_1; 367 } else { 368 mode = SOC_TD3_PORT_RATIO_DUAL_1_2; 369 } 370 } else if (num_lanes[0] == 2) { 371 if (num_lanes[2] == -1) { 372 mode = SOC_TD3_PORT_RATIO_DUAL_1_1; 373 } else { 374 mode = (speed_max[0] == 20000 || speed_max[0] == 21000 || 375 speed_max[0] == 50000 || speed_max[0] == 53000) ? 376 SOC_TD3_PORT_RATIO_TRI_023_2_1_1 : 377 SOC_TD3_PORT_RATIO_TRI_023_4_1_1; 378 } 379 } else if (num_lanes[2] == 2) { 380 if (num_lanes[0] == -1) { 381 mode = SOC_TD3_PORT_RATIO_DUAL_1_1; 382 } else { 383 mode = (speed_max[2] == 20000 || speed_max[2] == 21000 || 384 speed_max[2] == 50000 || speed_max[2] == 53000) ? 385 SOC_TD3_PORT_RATIO_TRI_012_1_1_2 : 386 SOC_TD3_PORT_RATIO_TRI_012_1_1_4; 387 } 388 } else { 389 mode = SOC_TD3_PORT_RATIO_QUAD; 390 } 391 392 *pm_mode = mode; 393 } 394 395 396 /*! @fn void _soc_td3_tdm_get_pipe_map( 397 int unit, 398 soc_port_schedule_state_t *sch_info, 399 uint32 *pipe_map) 400 @param unit Chip unit number. 401 @param sch_info Pointer to a soc_port_schedule_state_t struct variable. 402 @param pipe_map Returned pipe map. 403 @brief Returns pipe bitmap. 404 * Description: 405 For init, a pipe gets 1 if exists active port within that pipe. 406 For flexport, a pipe gets 1 if exists flexed port within that pipe. 407 */ 408 void 409 _soc_td3_tdm_get_pipe_map(int unit, 410 soc_port_schedule_state_t *sch_info, 411 uint32 *pipe_map) 412 { 413 uint32 port, pipe, i, pipe_bmap = 0; 414 415 if (sch_info->is_flexport == 0) { /* Init */ 416 for (port = 0; port < TRIDENT3_TDM_PHY_PORTS_PER_DEV; port++) { 417 if (sch_info->out_port_map.log_port_speed[port] > 0 ) { 418 pipe = port / TRIDENT3_TDM_PHY_PORTS_PER_PIPE; 419 pipe_bmap |= 1 << pipe; 420 } 421 } 422 } else { /* FlexPort */ 423 for (i = 0; i < sch_info->nport; i++) { 424 port = sch_info->resource[i].logical_port; 425 pipe = port / TRIDENT3_TDM_PHY_PORTS_PER_PIPE; 426 pipe_bmap |= 1 << pipe; 427 } 428 } 429 *pipe_map = pipe_bmap; 430 } 431 432 433 /*! @fn void _soc_td3_tdm_get_ovs_pipe_map( 434 int unit, 435 soc_port_schedule_state_t *sch_info, 436 uint32 *ovs_pipe_map) 437 @param unit Chip unit number. 438 @param sch_info Pointer to a soc_port_schedule_state_t struct variable. 439 @param ovs_pipe_map Returned pipe map. 440 @brief Returns OVS pipe bitmap. 441 * Description: 442 For init, a pipe gets 1 if exists oversub port within that pipe. 443 */ 444 void 445 _soc_td3_tdm_get_ovs_pipe_map(int unit, 446 soc_port_schedule_state_t *sch_info, 447 uint32 *ovs_pipe_map) 448 { 449 uint32 port, pipe, pipe_bmap = 0; 450 int is_ovs_map; 451 452 if (sch_info->is_flexport == 0) { /* Init */ 453 for (port = 0; port < TRIDENT3_TDM_PHY_PORTS_PER_DEV; port++) { 454 is_ovs_map = SOC_PBMP_MEMBER(sch_info->out_port_map.oversub_pbm, 455 port) ? 1 : 0; 456 if ((sch_info->out_port_map.log_port_speed[port] > 0) && 457 (1 == is_ovs_map) ) { 458 pipe = port / TRIDENT3_TDM_PHY_PORTS_PER_PIPE; 459 pipe_bmap |= 1 << pipe; 460 } 461 } 462 } 463 *ovs_pipe_map = pipe_bmap; 464 } 465 466 467 /*! @fn int _soc_td3_tdm_get_speed_ovs_class( 468 int unit, 469 int speed) 470 @param unit Chip unit number. 471 @param speed Speed 472 @return port_speed_class to be returned 473 @brief Help function to determine ovs class 474 * Description: 475 Oversubscription speed group class encoding 476 0 - 0 477 1 - 2 (1G/10G) 478 2 - 4 (20G) 479 3 - 5 (25G) 480 4 - 8 (40G) 481 5 - 10 (50G) 482 6 - 20 (100G) 483 */ 484 int 485 _soc_td3_tdm_get_speed_ovs_class(int unit, int speed) 486 { 487 int speed_class = 0; 488 489 if (speed >= 40000) { 490 if (speed >= 100000) { 491 speed_class = 6; 492 } else if (speed >= 50000) { 493 speed_class = 5; 494 } else { 495 speed_class = 4; 496 } 497 } else { 498 if (speed >= 25000) { 499 speed_class = 3; 500 } else if (speed >= 20000) { 501 speed_class = 2; 502 } else if (speed >= 10000) { 503 speed_class = 1; 504 } else if (speed >= 1000) { 505 speed_class = 1; 506 } 507 } 508 509 /* 1G and 10G are always treated as 25G. */ 510 if (speed_class == 1) { 511 speed_class = 3; 512 } 513 514 return (speed_class); 515 } 516 517 518 /*! @fn int _soc_td3_tdm_check_is_hsp_port_e( 519 int unit, 520 int speed) 521 @param unit Chip unit number. 522 @param speed Speed 523 @return 1->high speed port; 0->not high speed port; 524 @brief To determine the same port spacing for egress pipe 525 * Description: 526 Oversubscription speed group class encoding 527 0 - 0 528 1 - 2 (10G) 529 2 - 4 (20G) 530 3 - 5 (25G) 531 4 - 8 (40G) 532 5 - 10 (50G) 533 6 - 20 (100G) 534 */ 535 STATIC int 536 _soc_td3_tdm_check_is_hsp_port_e(int unit, int speed) 537 { 538 int speed_class, port_is_hsp = 0; 539 540 speed_class = _soc_td3_tdm_get_speed_ovs_class(unit, speed); 541 switch (speed_class) { 542 case 2: /* 20G */ 543 case 4: /* 40G */ 544 case 5: /* 50G */ 545 case 6: /* 100G */ 546 port_is_hsp = 1; 547 break; 548 default: 549 port_is_hsp = 0; 550 break; 551 } 552 553 return (port_is_hsp); 554 } 555 556 557 /*! @fn int _soc_td3_tdm_check_2nd_mgmt_enable( 558 int unit, 559 soc_port_schedule_state_t *sch_info) 560 @param unit Chip unit number. 561 @param sch_info Pointer to a soc_port_schedule_state_t struct variable. 562 @return 1-> 2nd management port enabled; 0 -> otherwise 563 @brief Help function to determine if 2nd management port is enabled. 564 */ 565 STATIC int 566 _soc_td3_tdm_check_2nd_mgmt_enable(int unit, 567 soc_port_schedule_state_t *sch_info) 568 { 569 int port; 570 int mgmt_port_cnt = 0; 571 int mgmt_2nd_port_en = 0; 572 573 SOC_PBMP_ITER(sch_info->in_port_map.management_pbm, port) { 574 mgmt_port_cnt++; 575 } 576 if (mgmt_port_cnt>1) { 577 mgmt_2nd_port_en = 1; 578 } 579 580 return (mgmt_2nd_port_en); 581 } 582 583 584 /*! @fn int _soc_td3_tdm_get_same_port_spacing_e( 585 int unit, 586 int speed) 587 @param unit Chip unit number. 588 @param speed Speed 589 @return same port spacing of the given speed port 590 @brief To determine the same port spacing for egress pipe 591 - 8 for high speed port 592 - 14 for not high speed port 593 */ 594 int 595 _soc_td3_tdm_get_same_port_spacing_e(int unit, int speed) 596 { 597 int port_same_spacing = 0; 598 599 if (_soc_td3_tdm_check_is_hsp_port_e(unit, speed) == 1) { 600 port_same_spacing = 8; 601 } else { 602 port_same_spacing = 14; 603 } 604 605 return (port_same_spacing); 606 } 607 608 609 /*! @fn int _soc_td3_tdm_calculation( 610 int unit, 611 soc_port_schedule_state_t *sch_info) 612 @param unit Chip unit number. 613 @param sch_info Pointer to a soc_port_schedule_state_t struct variable. 614 @brief API to calculate TDM tables. 615 */ 616 int 617 _soc_td3_tdm_calculation(int unit, soc_port_schedule_state_t *sch_info) 618 { 619 int i, j, pm_num, phy_port, lgc_port, phy_port_tmp; 620 int pipe, hpipe; 621 int lane, group, index; 622 int mgmt_pm_hg = 0, mgmt_mode = 0; 623 int tdm_idb_cal_len, tdm_mmu_cal_len, tdm_pipe_grp_num, tdm_pipe_grp_len; 624 int tdm_chk_en = 0; 625 int *tdm_idb_pipe_main, *tdm_mmu_pipe_main; 626 int **tdm_pipe_ovs_group; 627 tdm_soc_t _chip_pkg; 628 tdm_mod_t *_tdm_pkg; 629 uint32 port_speeds[TRIDENT3_TDM_PHY_PORTS_PER_DEV]; 630 uint32 port_states[TRIDENT3_TDM_PHY_PORTS_PER_DEV]; 631 int l_speed = 0, l_num_lanes = 0, prev_or_new = 1; 632 633 sal_memset(port_speeds, 0, TRIDENT3_TDM_PHY_PORTS_PER_DEV*sizeof(uint32)); 634 sal_memset(port_states, 0, TRIDENT3_TDM_PHY_PORTS_PER_DEV*sizeof(uint32)); 635 636 /* Remap input speeds to ETH bitrates */ 637 soc_trident3_port_schedule_speed_remap(unit, sch_info); 638 639 /* Set port states and speeds */ 640 for (lgc_port = 0; lgc_port < TRIDENT3_TDM_PHY_PORTS_PER_DEV; lgc_port++) { 641 phy_port = sch_info->in_port_map.port_l2p_mapping[lgc_port]; 642 if (phy_port < TRIDENT3_TDM_PHY_PORTS_PER_DEV) { 643 if (sch_info->in_port_map.log_port_speed[lgc_port] > 0 ) { 644 if (SOC_PBMP_MEMBER(sch_info->in_port_map.hg2_pbm,lgc_port)) { 645 port_states[phy_port] = 646 SOC_PBMP_MEMBER(sch_info->in_port_map.oversub_pbm, 647 lgc_port) ? PORT_STATE__OVERSUB_HG : 648 PORT_STATE__LINERATE_HG; 649 } else { 650 port_states[phy_port] = 651 SOC_PBMP_MEMBER(sch_info->in_port_map.oversub_pbm, 652 lgc_port) ? PORT_STATE__OVERSUB : 653 PORT_STATE__LINERATE; 654 } 655 656 soc_td3_tdm_get_log_port_speed(unit, sch_info, lgc_port, 657 prev_or_new, &l_speed, &l_num_lanes); 658 for (lane = 1; lane < l_num_lanes; lane++) { 659 phy_port_tmp = phy_port + lane; 660 if (phy_port_tmp < TRIDENT3_TDM_PHY_PORTS_PER_DEV) { 661 port_states[phy_port_tmp] = PORT_STATE__COMBINE; 662 } 663 } 664 port_speeds[phy_port] = l_speed; 665 } 666 if (SOC_PBMP_MEMBER(sch_info->in_port_map.management_pbm, lgc_port)) { 667 if (SOC_PBMP_MEMBER(sch_info->in_port_map.hg2_pbm, lgc_port)) { 668 mgmt_pm_hg = 1; /* HIGIG2 : ETHERNET */ 669 } 670 port_speeds[phy_port] = 0; 671 port_states[phy_port] = 0; 672 } 673 } 674 } 675 /* Print input config */ 676 if (LOG_CHECK(BSL_LS_SOC_TDM | BSL_INFO)) { 677 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 678 "frequency: %dMHz\n"), 679 sch_info->frequency)); 680 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 681 "%8s%8s%8s\n"), 682 "port", "speed", "state")); 683 for (phy_port = 0; phy_port < TRIDENT3_TDM_PHY_PORTS_PER_DEV; 684 phy_port++) { 685 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 686 "%8d%8d%8d\n"), 687 phy_port, port_speeds[phy_port]/1000, 688 port_states[phy_port])); 689 } 690 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "\n"))); 691 } 692 /* Initialize input variables for SW TDM Generation: 693 -- unit 694 -- num_ext_ports 695 -- state 696 -- speed 697 -- clk_freq 698 -- flex_port_en: 0->init, 1->flex 699 -- mgmt_pm_hg: 0->Ethernet mgmt, 1->HiGig2 mgmt 700 -- mgmt_mode: 0->two Ethernet mgmt ports 701 1->one Ethernet mgmt port 702 2->two Higig mgmt ports 703 3->one Higig mgmt port 704 */ 705 sal_memset(&_chip_pkg, 0, sizeof(tdm_soc_t)); 706 _chip_pkg.unit = unit; 707 _chip_pkg.num_ext_ports = TD3_NUM_EXT_PORTS; 708 _chip_pkg.state = sal_alloc((_chip_pkg.num_ext_ports)*sizeof(int), 709 "port state list"); 710 if (_chip_pkg.state == NULL) { 711 return SOC_E_MEMORY; 712 } 713 _chip_pkg.speed = sal_alloc((_chip_pkg.num_ext_ports)*sizeof(int), 714 "port speed list"); 715 if (_chip_pkg.speed == NULL) { 716 sal_free(_chip_pkg.state); 717 return SOC_E_MEMORY; 718 } 719 for (index = 0; index < _chip_pkg.num_ext_ports; index++) { 720 _chip_pkg.state[index] = 0; 721 _chip_pkg.speed[index] = 0; 722 } 723 for (index = 0; index < _chip_pkg.num_ext_ports && 724 index < TRIDENT3_TDM_PHY_PORTS_PER_DEV; index++) { 725 _chip_pkg.state[index] = port_states[index]; 726 _chip_pkg.speed[index] = port_speeds[index]; 727 } 728 /* Shift port state to left one position; required by C_TDM */ 729 for (index = 1; index < _chip_pkg.num_ext_ports; index++) { 730 _chip_pkg.state[index - 1] = _chip_pkg.state[index]; 731 } 732 _chip_pkg.clk_freq = sch_info->frequency; 733 _chip_pkg.flex_port_en = sch_info->is_flexport; 734 _chip_pkg.soc_vars.td3.tdm_chk_en= tdm_chk_en; 735 _chip_pkg.soc_vars.td3.mgmt_pm_hg= mgmt_pm_hg; 736 mgmt_mode = mgmt_pm_hg == 1 ? 2 : 0; 737 _chip_pkg.soc_vars.td3.mgmt_mode = 738 (_soc_td3_tdm_check_2nd_mgmt_enable(unit, sch_info) == 1) ? 739 (mgmt_mode + 0) : (mgmt_mode + 1); 740 741 /* Populate TDM tables by invoking SW TDM API */ 742 /* coverity[dont_call : FALSE] */ 743 _tdm_pkg = _soc_set_tdm_tbl(SOC_SEL_TDM(&_chip_pkg)); 744 745 /* Free the memory allocated to port states and speeds */ 746 sal_free(_chip_pkg.state); 747 sal_free(_chip_pkg.speed); 748 749 /* Copy TDM result into output structure */ 750 if (_tdm_pkg == NULL) { 751 LOG_CLI((BSL_META_U(unit, 752 "Unsupported config for TDM calendar generation\n"))); 753 return SOC_E_FAIL; 754 } else { 755 /* IDB calendar (0-3), MMU calendar (4-7) */ 756 for (pipe = 0; pipe < TRIDENT3_TDM_PIPES_PER_DEV; pipe++) { 757 switch (pipe) { 758 /* IDB_PIPE_0, MMU_PIPE_0 */ 759 case 0: 760 tdm_pipe_ovs_group = _tdm_pkg->_chip_data.cal_0.cal_grp; 761 tdm_pipe_grp_num = _tdm_pkg->_chip_data.cal_0.grp_num; 762 tdm_pipe_grp_len = _tdm_pkg->_chip_data.cal_0.grp_len; 763 tdm_idb_pipe_main = _tdm_pkg->_chip_data.cal_0.cal_main; 764 tdm_idb_cal_len = _tdm_pkg->_chip_data.cal_0.cal_len; 765 tdm_mmu_pipe_main = _tdm_pkg->_chip_data.cal_4.cal_main; 766 tdm_mmu_cal_len = _tdm_pkg->_chip_data.cal_4.cal_len; 767 break; 768 /* IDB_PIPE_1, MMU_PIPE_1 */ 769 default: 770 tdm_pipe_ovs_group = _tdm_pkg->_chip_data.cal_1.cal_grp; 771 tdm_pipe_grp_num = _tdm_pkg->_chip_data.cal_1.grp_num; 772 tdm_pipe_grp_len = _tdm_pkg->_chip_data.cal_1.grp_len; 773 tdm_idb_pipe_main = _tdm_pkg->_chip_data.cal_1.cal_main; 774 tdm_idb_cal_len = _tdm_pkg->_chip_data.cal_1.cal_len; 775 tdm_mmu_pipe_main = _tdm_pkg->_chip_data.cal_5.cal_main; 776 tdm_mmu_cal_len = _tdm_pkg->_chip_data.cal_5.cal_len; 777 break; 778 } 779 if (tdm_pipe_ovs_group == NULL || 780 tdm_idb_pipe_main == NULL || 781 tdm_mmu_pipe_main == NULL) { 782 LOG_CLI((BSL_META_U(unit, 783 "Unsupported config for TDM calendar generation\n"))); 784 tdm_td3_main_free(_tdm_pkg); 785 sal_free(_tdm_pkg); 786 return SOC_E_FAIL; 787 } else { 788 /* IDB TDM main calendar */ 789 for (index = 0; index < tdm_idb_cal_len; index++) { 790 sch_info->tdm_ingress_schedule_pipe[pipe].tdm_schedule_slice[ 791 0].linerate_schedule[index] = tdm_idb_pipe_main[index]; 792 } 793 /* MMU TDM main calendar */ 794 for (index = 0; index < tdm_mmu_cal_len; index++) { 795 sch_info->tdm_egress_schedule_pipe[pipe].tdm_schedule_slice[ 796 0].linerate_schedule[index] = tdm_mmu_pipe_main[index]; 797 } 798 799 /* IDB and MMU OverSub Groups */ 800 for (i = 0; i < tdm_pipe_grp_num; i++) { 801 /* Group 0:5 -> hpipe 0, Group 6:11 -> hpipe1 */ 802 hpipe = i / TRIDENT3_TDM_OVS_GROUPS_PER_HPIPE; 803 group = i % TRIDENT3_TDM_OVS_GROUPS_PER_HPIPE; 804 for (j = 0; j < tdm_pipe_grp_len; j++) { 805 sch_info->tdm_ingress_schedule_pipe[ 806 pipe].tdm_schedule_slice[hpipe].oversub_schedule[ 807 group][j] = tdm_pipe_ovs_group[i][j]; 808 sch_info->tdm_egress_schedule_pipe[ 809 pipe].tdm_schedule_slice[hpipe].oversub_schedule[ 810 group][j] = tdm_pipe_ovs_group[i][j]; 811 } 812 } 813 814 /* Packet shaper */ 815 for (hpipe = 0; hpipe < 2; hpipe++) { 816 for (j = 0; j < TD3_SHAPING_GRP_LEN; j++) { 817 sch_info->tdm_ingress_schedule_pipe[ 818 pipe].tdm_schedule_slice[hpipe].pkt_sch_or_ovs_space[ 819 0][j] = tdm_pipe_ovs_group[hpipe+ 820 TD3_SHAPING_GRP_IDX_0][j]; 821 } 822 } 823 } 824 } 825 /* Re-evaluate this at FlexPort; 826 * Before calling FlexPort sch_info->in_port_map.port_p2PBLK_inst_mapping should be copied in pm_num_to_pblk 827 * After FlexPort pm_num_to_pblk should be copied back to sch_info->out_port_map.port_p2PBLK_inst_mapping 828 */ 829 sal_memset(sch_info->out_port_map.port_p2PBLK_inst_mapping, 830 0, sizeof(int) * SOC_MAX_NUM_PORTS); 831 for (pm_num = 0; pm_num < TD3_NUM_PHY_PM; pm_num++) { 832 for (lane = 0; lane < TRIDENT3_TDM_PORTS_PER_PBLK; lane++) { 833 sch_info->out_port_map.port_p2PBLK_inst_mapping[ 834 (pm_num * TRIDENT3_TDM_PORTS_PER_PBLK) + 1 + lane] = 835 _tdm_pkg->_chip_data.soc_pkg.soc_vars.td3.pm_num_to_pblk[pm_num]; 836 } 837 } 838 /* Free the memory allocated in TDM algorithm code */ 839 tdm_td3_main_free(_tdm_pkg); /* This function frees all pointers allocated during _soc_set_tdm_tbl call */ 840 sal_free(_tdm_pkg); 841 } 842 843 /* Print TDM result */ 844 if (LOG_CHECK(BSL_LS_SOC_TDM | BSL_INFO)) { 845 for (pipe = 0; pipe < TRIDENT3_TDM_PIPES_PER_DEV; pipe++) { 846 /* IDB TDM main calendar */ 847 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 848 "Pipe %d [IDB TDM main calendar]\n"), 849 pipe)); 850 for (index = 0; index < MAX_CAL_LEN; index++) { 851 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 852 " %3d"), 853 sch_info->tdm_ingress_schedule_pipe[ 854 pipe].tdm_schedule_slice[0].linerate_schedule[index])); 855 if (index % 16 == 0 && index > 0) { 856 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "\n"))); 857 } 858 } 859 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "\n"))); 860 /* Oversub groups */ 861 for (hpipe = 0; hpipe < TRIDENT3_TDM_HPIPES_PER_PIPE; hpipe++) { 862 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 863 "Pipe %d Half-Pipe %d [IDB TDM Oversub Groups]\n"), 864 pipe, hpipe)); 865 for (group = 0; group < TRIDENT3_TDM_OVS_GROUPS_PER_HPIPE; 866 group++) { 867 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 868 "oversub group %d: "), 869 group)); 870 for (index = 0; index < TRIDENT3_TDM_OVS_GROUP_LENGTH; 871 index++) { 872 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 873 " %3d"), 874 sch_info->tdm_ingress_schedule_pipe[pipe].tdm_schedule_slice[ 875 hpipe].oversub_schedule[group][index])); 876 } 877 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "\n"))); 878 } 879 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "\n"))); 880 } 881 /* Packet scheduler */ 882 for (hpipe = 0; hpipe < TRIDENT3_TDM_HPIPES_PER_PIPE; hpipe++) { 883 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 884 "Pipe %d Half-Pipe %d [IDB TDM PKT SCHEDULER]\n"), 885 pipe, hpipe)); 886 for (index = 0; index < TD3_SHAPING_GRP_LEN; index++) { 887 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 888 " %3d"), 889 sch_info->tdm_ingress_schedule_pipe[ 890 pipe].tdm_schedule_slice[hpipe].pkt_sch_or_ovs_space[0][index])); 891 if (index % 16 == 0 && index > 0) { 892 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "\n"))); 893 } 894 } 895 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "\n"))); 896 } 897 /* MMU TDM main calendar */ 898 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 899 "Pipe %d [MMU TDM main calendar]:\n"), pipe)); 900 for (index = 0; index < MAX_CAL_LEN; index++) { 901 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, " %3d"), 902 sch_info->tdm_egress_schedule_pipe[pipe]. 903 tdm_schedule_slice[0].linerate_schedule[index])); 904 if (index % 16 == 0 && index > 0) { 905 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "\n"))); 906 } 907 } 908 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "\n"))); 909 } 910 } 911 912 /* If init then just copy in_port_map to out_port_map*/ 913 if (sch_info->is_flexport == 0) { 914 for (i= 0; i< SOC_MAX_NUM_PORTS;i++) { 915 sch_info->out_port_map.log_port_speed[i] = 916 sch_info->in_port_map.log_port_speed[i]; 917 sch_info->out_port_map.port_p2l_mapping[i] = 918 sch_info->in_port_map.port_p2l_mapping[i]; 919 sch_info->out_port_map.port_l2p_mapping[i] = 920 sch_info->in_port_map.port_l2p_mapping[i]; 921 sch_info->out_port_map.port_p2m_mapping[i] = 922 sch_info->in_port_map.port_p2m_mapping[i]; 923 sch_info->out_port_map.port_num_lanes[i] = 924 sch_info->in_port_map.port_num_lanes[i]; 925 sch_info->out_port_map.port_l2i_mapping[i] = 926 sch_info->in_port_map.port_l2i_mapping[i]; 927 } 928 for (i = 0; i < SOC_MAX_NUM_MMU_PORTS; i++) { 929 sch_info->out_port_map.port_m2p_mapping[i] = 930 sch_info->in_port_map.port_m2p_mapping[i]; 931 } 932 for (i = 0; i < _SHR_PBMP_WORD_MAX; i++) { 933 sch_info->out_port_map.physical_pbm.pbits[i] = 934 sch_info->in_port_map.physical_pbm.pbits[i]; 935 sch_info->out_port_map.hg2_pbm.pbits[i] = 936 sch_info->in_port_map.hg2_pbm.pbits[i]; 937 sch_info->out_port_map.management_pbm.pbits[i] = 938 sch_info->in_port_map.management_pbm.pbits[i]; 939 sch_info->out_port_map.oversub_pbm.pbits[i] = 940 sch_info->in_port_map.oversub_pbm.pbits[i]; 941 } 942 } 943 /* 944 * else { 945 * HERE future handling of FlexPort between in_port_map to out_port_map 946 * } 947 */ 948 949 _soc_td3_tdm_print_schedule_state(unit, sch_info); 950 return SOC_E_NONE; 951 } 952 953 954 /*! @fn int _soc_td3_tdm_set_idb_calendar( 955 int unit, 956 soc_port_schedule_state_t *sch_info) 957 @param unit Chip unit number. 958 @param sch_info Pointer to a soc_port_schedule_state_t struct variable. 959 @brief API to initialize the TD3 IDB main calendar. 960 */ 961 int 962 _soc_td3_tdm_set_idb_calendar(int unit, soc_port_schedule_state_t *sch_info) 963 { 964 uint32 pipe_map; 965 uint32 cal_len; 966 soc_mem_t mem; 967 soc_reg_t reg; 968 soc_field_t cal_end_field; 969 int pipe, slot, id, length, calendar_id; 970 int phy_port, idb_port; 971 int port; 972 uint32 rval; 973 uint32 memfld; 974 uint32 entry[SOC_MAX_MEM_WORDS]; 975 uint32 mem_indx; 976 static const soc_mem_t idb_tdm_cal_mem[TRIDENT3_TDM_PIPES_PER_DEV][2] = { 977 {IS_TDM_CALENDAR0_PIPE0m, IS_TDM_CALENDAR1_PIPE0m}, 978 {IS_TDM_CALENDAR0_PIPE1m, IS_TDM_CALENDAR1_PIPE1m} 979 }; 980 static const soc_reg_t idb_tdm_cfg_reg[TRIDENT3_TDM_PIPES_PER_DEV] = { 981 IS_TDM_CONFIG_PIPE0r, IS_TDM_CONFIG_PIPE1r 982 }; 983 static const soc_field_t calendar_end_fields[] = { 984 CAL0_ENDf, CAL1_ENDf 985 }; 986 987 _soc_td3_tdm_get_pipe_map(unit, sch_info, &pipe_map); 988 sal_memset(entry, 0, sizeof(uint32) * soc_mem_entry_words(unit, 989 IS_TDM_CALENDAR0_PIPE0m)); 990 991 for (pipe = 0; pipe < NUM_PIPE(unit); pipe++) { 992 /* coverity[overrun-local : FALSE] */ 993 reg = idb_tdm_cfg_reg[pipe]; 994 /* Pipe is empty */ 995 if ((pipe_map & (1 << pipe)) == 0) { 996 /* At init, even if the pipe doesn't have active ports, 997 * enable scheduler for sbus accesses to PP IPIPE 998 */ 999 if (sch_info->is_flexport == 0) { 1000 rval = 0; 1001 soc_reg_field_set(unit, reg, &rval, ENABLEf, 1); 1002 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, reg, REG_PORT_ANY, 1003 0, rval)); 1004 } 1005 continue; 1006 } 1007 /* Determine calendar_id : 0 or 1 */ 1008 if (sch_info->is_flexport == 1) { /* choose "the other calendar" */ 1009 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, reg, REG_PORT_ANY, 1010 0, &rval)); 1011 calendar_id = soc_reg_field_get(unit, reg, rval, CURR_CALf) ^ 1; 1012 } else { 1013 /* At init use calendar_id=0 */ 1014 calendar_id = 0; 1015 /* Also, before writing the TDM calendar entries, make sure 1016 * calendar is disabled again; 1017 * IDB scheduler may be already enabled at this point to allow 1018 * sbus access to IPIPE for reset purpose (Sec. 3.1.2 SW_init doc) 1019 */ 1020 rval = 0; 1021 soc_reg_field_set(unit, reg, &rval, ENABLEf, 0); 1022 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, reg, REG_PORT_ANY, 0, rval)); 1023 } 1024 /* coverity[overrun-local : FALSE] */ 1025 mem = idb_tdm_cal_mem[pipe][calendar_id]; 1026 cal_end_field = calendar_end_fields[calendar_id]; 1027 1028 /* TDM Calendar is always taken from slice 0 */ 1029 cal_len = sch_info->tdm_ingress_schedule_pipe[pipe].tdm_schedule_slice[ 1030 0].cal_len; 1031 for (length = cal_len; length > 0; length--) { 1032 if (sch_info->tdm_ingress_schedule_pipe[pipe].tdm_schedule_slice[ 1033 0].linerate_schedule[length - 1] != TD3_NUM_EXT_PORTS) { 1034 break; 1035 } 1036 } 1037 for (slot = 0; slot < length; slot += 2) { 1038 /* EVEN */ 1039 phy_port = sch_info->tdm_ingress_schedule_pipe[ 1040 pipe].tdm_schedule_slice[0].linerate_schedule[slot]; 1041 if (phy_port == TD3_OVSB_TOKEN) { 1042 idb_port = TRIDENT3_TDM_IDB_OVSB_TOKEN; 1043 } else if (phy_port == TD3_IDL1_TOKEN) { 1044 idb_port = TRIDENT3_TDM_IDB_SBUS_TOKEN; 1045 } else if (phy_port == TD3_IDL2_TOKEN) { 1046 idb_port = TRIDENT3_TDM_IDB_UNUSED_TOKEN; 1047 } else if (phy_port == TD3_NULL_TOKEN) { 1048 idb_port = TRIDENT3_TDM_IDB_NULL_TOKEN; 1049 } else if (phy_port >= TD3_NUM_EXT_PORTS) { 1050 idb_port = TRIDENT3_TDM_IDB_UNUSED_TOKEN; 1051 } else if (phy_port == TD3_MGM1_TOKEN) { 1052 /* TDM code always allocates slots for management port. 1053 * If mgmt ports are omitted from config, this mapping 1054 * is not set up. 1055 */ 1056 idb_port = TRIDENT3_TDM_IDB_MGMT1_TOKEN; 1057 } else { 1058 port = sch_info->out_port_map.port_p2l_mapping[phy_port]; 1059 idb_port = sch_info->out_port_map.port_l2i_mapping[port] & 0x7f; 1060 } 1061 if (idb_port > 63) { /* Not a general front panel port */ 1062 id = 0xf; 1063 } else { 1064 id = (phy_port - 1) / TRIDENT3_TDM_PORTS_PER_PBLK; 1065 } 1066 memfld = idb_port & 0x7f; /* [0,69] && 127 */ 1067 soc_mem_field_set(unit, mem, entry, PORT_NUM_EVENf, &memfld); 1068 memfld = id & 0xf; 1069 soc_mem_field_set(unit, mem, entry, PHY_PORT_ID_EVENf, &memfld); 1070 /* ODD */ 1071 phy_port = sch_info->tdm_ingress_schedule_pipe[pipe].tdm_schedule_slice[0].linerate_schedule[slot + 1]; 1072 if (phy_port == TD3_OVSB_TOKEN) { 1073 idb_port = TRIDENT3_TDM_IDB_OVSB_TOKEN; 1074 } else if (phy_port == TD3_IDL1_TOKEN) { 1075 idb_port = TRIDENT3_TDM_IDB_SBUS_TOKEN; 1076 } else if (phy_port == TD3_IDL2_TOKEN) { 1077 idb_port = TRIDENT3_TDM_IDB_UNUSED_TOKEN; 1078 } else if (phy_port == TD3_NULL_TOKEN) { 1079 idb_port = TRIDENT3_TDM_IDB_NULL_TOKEN; 1080 } else if (phy_port >= TD3_NUM_EXT_PORTS) { 1081 idb_port = TRIDENT3_TDM_IDB_UNUSED_TOKEN; 1082 } else if (phy_port == TD3_MGM1_TOKEN) { 1083 /* TDM code always allocates slots for management port. 1084 * If mgmt ports are omitted from config, this mapping 1085 * is not set up. 1086 */ 1087 idb_port = TRIDENT3_TDM_IDB_MGMT1_TOKEN; 1088 } else { 1089 port = sch_info->out_port_map.port_p2l_mapping[phy_port]; 1090 idb_port = sch_info->out_port_map.port_l2i_mapping[port] & 0x7f; 1091 } 1092 if (idb_port > 63) { /* Not a general front panel port */ 1093 id = 0xf; 1094 } else { 1095 id = (phy_port - 1) / TRIDENT3_TDM_PORTS_PER_PBLK; 1096 } 1097 memfld = idb_port & 0x7f; /* [0,69] && 127 */ 1098 soc_mem_field_set(unit, mem, entry, PORT_NUM_ODDf, &memfld); 1099 memfld = id & 0xf; 1100 soc_mem_field_set(unit, mem, entry, PHY_PORT_ID_ODDf, &memfld); 1101 /* Memory entry */ 1102 mem_indx = slot / 2; 1103 SOC_IF_ERROR_RETURN 1104 (soc_mem_write(unit, mem, MEM_BLOCK_ALL, mem_indx, entry)); 1105 } 1106 1107 /* set for 2nd management port */ 1108 if (_soc_td3_tdm_check_2nd_mgmt_enable(unit, sch_info) == 1 && 1109 pipe == (TRIDENT3_TDM_PIPES_PER_DEV - 1)) { 1110 /* reg: IS_TDM_CONFIG_PIPExr */ 1111 soc_reg_field_set(unit, reg, &rval, MGMT_2ND_PORT_ENABLEf, 1); 1112 } 1113 1114 soc_reg_field_set(unit, reg, &rval, cal_end_field, length-1); 1115 soc_reg_field_set(unit, reg, &rval, CURR_CALf, calendar_id); 1116 soc_reg_field_set(unit, reg, &rval, ENABLEf, 1); 1117 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, reg, REG_PORT_ANY, 0, rval)); 1118 } 1119 1120 return SOC_E_NONE; 1121 } 1122 1123 1124 /*! @fn int _soc_td3_tdm_set_idb_hsp( 1125 int unit, 1126 soc_port_schedule_state_t *sch_info) 1127 @param unit Chip unit number. 1128 @param sch_info Pointer to a soc_port_schedule_state_t struct variable. 1129 @brief API to initialize the TD3 IDB HSP. 1130 */ 1131 int 1132 _soc_td3_tdm_set_idb_hsp(int unit, soc_port_schedule_state_t *sch_info) 1133 { 1134 soc_reg_t reg; 1135 uint32 pipe_map; 1136 int pipe; 1137 uint32 pmap; 1138 uint32 rval = 0; 1139 1140 static const soc_reg_t idb_tdm_hsp[TRIDENT3_TDM_PIPES_PER_DEV][2] = { 1141 {IS_TDM_HSP_0_PIPE0r, IS_TDM_HSP_0_PIPE1r}, 1142 {IS_TDM_HSP_1_PIPE0r, IS_TDM_HSP_1_PIPE1r} 1143 }; 1144 1145 /* IDB always configures PORT_BMPf field for idb_tdm_hsp regs 1146 * to 0xFFFF_FFFF_FFFF_FFFF, independent of the port's speed. 1147 */ 1148 pmap = 0xffffffff; /* up to 32 ports */ 1149 1150 _soc_td3_tdm_get_pipe_map(unit, sch_info, &pipe_map); 1151 for (pipe = 0; pipe < TRIDENT3_TDM_PIPES_PER_DEV; pipe++) { 1152 if (!(pipe_map & (1 << pipe))) { 1153 continue; 1154 } 1155 reg = idb_tdm_hsp[pipe][0]; 1156 soc_reg_field_set(unit, reg, &rval, PORT_BMPf, pmap); 1157 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, reg, REG_PORT_ANY, 0, rval)); 1158 1159 reg = idb_tdm_hsp[pipe][1]; 1160 soc_reg_field_set(unit, reg, &rval, PORT_BMPf, pmap); 1161 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, reg, REG_PORT_ANY, 0, rval)); 1162 } 1163 1164 return SOC_E_NONE; 1165 } 1166 1167 1168 /*! @fn int _soc_td3_tdm_set_idb_ppe_credit( 1169 int unit, 1170 soc_port_schedule_state_t 1171 *sch_info, 1172 int full_credit_threshold_0, 1173 int opp_credit_threshold_0, 1174 int full_credit_threshold_1, 1175 int opp_credit_threshold_1 ) 1176 @param unit Chip unit number. 1177 @param sch_info Pointer to a soc_port_schedule_state_t struct variable. 1178 @param full_credit_threshold_0 1179 @param opp_credit_threshold_0 1180 @param full_credit_threshold_1 1181 @param opp_credit_threshold_1 1182 @brief API to initialize the TD3 IDB PPE Credit Config register. 1183 Regs/Mems configured:PPE_CREDIT_CONFIG_PIPE<pipe> 1184 */ 1185 int 1186 _soc_td3_tdm_set_idb_ppe_credit(int unit, 1187 soc_port_schedule_state_t *sch_info, 1188 int full_credit_threshold_0, 1189 int opp_credit_threshold_0, 1190 int full_credit_threshold_1, 1191 int opp_credit_threshold_1 ) 1192 { 1193 soc_reg_t reg; 1194 uint32 pipe_map; 1195 int pipe; 1196 uint32 rval; 1197 static const soc_reg_t idb_ppe_credit[TRIDENT3_TDM_PIPES_PER_DEV] = { 1198 PPE_CREDIT_CONFIG_PIPE0r, PPE_CREDIT_CONFIG_PIPE1r 1199 }; 1200 1201 _soc_td3_tdm_get_pipe_map(unit, sch_info, &pipe_map); 1202 1203 for (pipe = 0; pipe < TRIDENT3_TDM_PIPES_PER_DEV; pipe++) { 1204 if (!(pipe_map & (1 << pipe))) { 1205 continue; 1206 } 1207 reg = idb_ppe_credit[pipe]; 1208 rval = 0; 1209 /*SOC_IF_ERROR_RETURN(soc_reg32_get(unit, reg, REG_PORT_ANY, 0, &rval));*/ 1210 soc_reg_field_set(unit, reg, &rval, FULL_CREDIT_THRESHOLD_0f, 1211 full_credit_threshold_0); 1212 soc_reg_field_set(unit, reg, &rval, OPP_CREDIT_THRESHOLD_0f, 1213 opp_credit_threshold_0); 1214 soc_reg_field_set(unit, reg, &rval, FULL_CREDIT_THRESHOLD_1f, 1215 full_credit_threshold_1); 1216 soc_reg_field_set(unit, reg, &rval, OPP_CREDIT_THRESHOLD_1f, 1217 opp_credit_threshold_1); 1218 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, reg, REG_PORT_ANY, 0, 1219 rval)); 1220 } 1221 1222 return SOC_E_NONE; 1223 } 1224 1225 1226 /*! @fn int _soc_td3_tdm_set_idb_opportunistic( 1227 int unit, 1228 soc_port_schedule_state_t *sch_info, 1229 int cpu_op_en, 1230 int lb_opp_en, 1231 int opp1_port_en, 1232 int opp2_port_en, 1233 int opp_ovr_sub_en) 1234 @param unit Chip unit number. 1235 @param sch_info Pointer to a soc_port_schedule_state_t struct variable. 1236 @param cpu_op_en 1237 @param lb_opp_en 1238 @param opp1_port_en 1239 @param opp2_port_en 1240 @param opp_ovr_sub_en 1241 @brief API to initialize the TD3 IDB Opportunistic related registers 1242 Regs/Mems configured: IS_CPU_LB_OPP_CFG_PIPE<pipe> 1243 IS_OPP_SCHED_CFG_PIPE<pipe> 1244 */ 1245 int 1246 _soc_td3_tdm_set_idb_opportunistic(int unit, 1247 soc_port_schedule_state_t *sch_info, 1248 int cpu_op_en, 1249 int lb_opp_en, 1250 int opp1_port_en, 1251 int opp2_port_en, 1252 int opp_ovr_sub_en) 1253 { 1254 soc_reg_t reg; 1255 uint32 pipe_map; 1256 int pipe; 1257 uint32 rval; 1258 static const soc_reg_t idb_cpu_lb_opp_cfg[TRIDENT3_TDM_PIPES_PER_DEV] = { 1259 IS_CPU_LB_OPP_CFG_PIPE0r, IS_CPU_LB_OPP_CFG_PIPE1r 1260 }; 1261 static const soc_reg_t idb_opp_sched_cfg[TRIDENT3_TDM_PIPES_PER_DEV] = { 1262 IS_OPP_SCHED_CFG_PIPE0r, IS_OPP_SCHED_CFG_PIPE1r 1263 }; 1264 1265 _soc_td3_tdm_get_pipe_map(unit, sch_info, &pipe_map); 1266 1267 for (pipe = 0; pipe < NUM_PIPE(unit); pipe++) { 1268 if ((pipe_map & (1 << pipe)) == 0) { 1269 /* Enable OPP1 to enable sbus access to the rest of IPIPE*/ 1270 reg = idb_opp_sched_cfg[pipe]; 1271 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, reg, REG_PORT_ANY, 0, &rval)); 1272 soc_reg_field_set(unit, reg, &rval, OPP1_PORT_ENf, 1273 (opp1_port_en == 1) ? 1 : 0); 1274 soc_reg_field_set(unit, reg, &rval, OPP1_SPACINGf, 8); 1275 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, reg, REG_PORT_ANY, 0, rval)); 1276 continue; 1277 } 1278 1279 reg = idb_cpu_lb_opp_cfg[pipe]; 1280 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, reg, REG_PORT_ANY, 0, &rval)); 1281 soc_reg_field_set(unit, reg, &rval, CPU_OPP_ENf, 1282 (cpu_op_en == 1) ? 1 : 0); 1283 soc_reg_field_set(unit, reg, &rval, LB_OPP_ENf, 1284 (lb_opp_en == 1) ? 1 : 0); 1285 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, reg, REG_PORT_ANY, 0, rval)); 1286 1287 reg = idb_opp_sched_cfg[pipe]; 1288 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, reg, REG_PORT_ANY, 0, &rval)); 1289 soc_reg_field_set(unit, reg, &rval, OPP1_PORT_ENf, 1290 (opp1_port_en == 1) ? 1 : 0); 1291 soc_reg_field_set(unit, reg, &rval, OPP1_SPACINGf, 8); 1292 soc_reg_field_set(unit, reg, &rval, OPP2_PORT_ENf, 1293 (opp2_port_en == 1) ? 1 : 0); 1294 soc_reg_field_set(unit, reg, &rval, OPP2_SPACINGf, 0); 1295 soc_reg_field_set(unit, reg, &rval, OPP_OVR_SUB_ENf, 1296 (opp_ovr_sub_en == 1) ? 1 : 0); 1297 soc_reg_field_set(unit, reg, &rval, OPP_STRICT_PRIf, 1); 1298 soc_reg_field_set(unit, reg, &rval, DISABLE_PORT_NUMf, 67); /* NULL port */ 1299 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, reg, REG_PORT_ANY, 0, rval)); 1300 } 1301 1302 return SOC_E_NONE; 1303 } 1304 1305 1306 /*! @fn int _soc_td3_tdm_set_idb_pkt_calendar( 1307 int unit, 1308 soc_port_schedule_state_t *sch_info) 1309 @param unit Chip unit number. 1310 @param sch_info Pointer to a soc_port_schedule_state_t struct variable. 1311 @brief API to initialize the TD3 IDB Packet Shaper calendar. 1312 Regs/Mems configured: IDB PKT_SCH_CALENDAR 1313 */ 1314 int 1315 _soc_td3_tdm_set_idb_pkt_calendar(int unit, 1316 soc_port_schedule_state_t *sch_info) 1317 { 1318 uint32 pipe_map; 1319 soc_mem_t mem; 1320 int pipe, slot, hpipe; 1321 int port, phy_port, idb_port; 1322 uint32 memfld; 1323 uint32 entry[SOC_MAX_MEM_WORDS]; 1324 static const soc_mem_t idb_pkt_shaper_mems[TRIDENT3_TDM_PIPES_PER_DEV][2] = { 1325 {PKT_SCH_CALENDAR0_PIPE0m, PKT_SCH_CALENDAR1_PIPE0m}, 1326 {PKT_SCH_CALENDAR0_PIPE1m, PKT_SCH_CALENDAR1_PIPE1m} 1327 }; 1328 1329 _soc_td3_tdm_get_pipe_map(unit, sch_info, &pipe_map); 1330 1331 for (pipe = 0; pipe < TRIDENT3_TDM_PIPES_PER_DEV; pipe++) { 1332 if (!(pipe_map & (1 << pipe))) { 1333 continue; 1334 } 1335 /* Configure packet shaper calendar */ 1336 for (hpipe = 0; hpipe < TRIDENT3_TDM_HPIPES_PER_PIPE; hpipe++) { 1337 mem = idb_pkt_shaper_mems[pipe][hpipe]; 1338 for (slot = 0; slot < TD3_SHAPING_GRP_LEN; slot ++) { 1339 phy_port = sch_info->tdm_ingress_schedule_pipe[ 1340 pipe].tdm_schedule_slice[hpipe].pkt_sch_or_ovs_space[0][slot]; 1341 if ((phy_port >= TD3_NUM_EXT_PORTS) || (phy_port <= 0)) { 1342 idb_port = TRIDENT3_TDM_IDB_UNUSED_TOKEN; 1343 } else { 1344 port = sch_info->in_port_map.port_p2l_mapping[phy_port]; 1345 idb_port = sch_info->in_port_map.port_l2i_mapping[port] & 0x1f; 1346 } 1347 sal_memset(entry, 0, sizeof(uint32) * soc_mem_entry_words(unit, 1348 PKT_SCH_CALENDAR0_PIPE0m)); 1349 memfld = idb_port & 0x3f; 1350 soc_mem_field_set(unit, mem, entry, PORT_NUMf, &memfld); 1351 SOC_IF_ERROR_RETURN(soc_mem_write(unit, mem, MEM_BLOCK_ALL, 1352 slot, entry)); 1353 } 1354 } 1355 } 1356 1357 return SOC_E_NONE; 1358 } 1359 1360 1361 /*! @fn int _soc_td3_tdm_set_ovs_group_sel( 1362 int unit, 1363 soc_port_schedule_state_t *sch_info, 1364 int set_idb, 1365 int set_mmu) 1366 @param unit Chip unit number. 1367 @param sch_info : Pointer to a soc_port_schedule_state_t struct variable. 1368 @param set_idb if 1 then IDB OVS tables are configured 1369 @param set_mmu if 1 then MMU OVS tables are configured 1370 @brief API to initialize the TD3 MMU &/or IDB OVS tables. 1371 Regs/Mems configured: IDB HPIPE0/1_OVR_SUB_GRP_CFG, 1372 HPIPE0/1_OVR_SUB_GRP_CFG 1373 PBLK<n>_CALENDAR 1374 */ 1375 int 1376 _soc_td3_tdm_set_ovs_group_sel(int unit, 1377 soc_port_schedule_state_t *sch_info, 1378 int set_idb, int set_mmu) 1379 { 1380 uint32 pipe_map, ovs_pipe_map; 1381 soc_reg_t reg, reg1; 1382 int pipe, hpipe, group, lane, slot, id = 0, mode; 1383 int port, phy_port, phy_port_base, idb_port, mmu_port, inst; 1384 int speed_max; 1385 uint32 rval, rval1; 1386 int pblks[TRIDENT3_TDM_PIPES_PER_DEV][2][TRIDENT3_TDM_PBLKS_PER_HPIPE]; 1387 int pm_num, pblk_cal_idx; 1388 int pblk_valid, pblk_spacing; 1389 int port_speed_class, port_same_spacing, port_sister_spacing; 1390 int l_speed = 0, l_num_lanes = 0, prev_or_new = 0; 1391 1392 static const soc_reg_t idb_grp_cfg_regs[TRIDENT3_TDM_PIPES_PER_DEV][2] = { 1393 {IS_HPIPE0_OVR_SUB_GRP_CFG_PIPE0r, IS_HPIPE1_OVR_SUB_GRP_CFG_PIPE0r}, 1394 {IS_HPIPE0_OVR_SUB_GRP_CFG_PIPE1r, IS_HPIPE1_OVR_SUB_GRP_CFG_PIPE1r} 1395 }; 1396 1397 static const soc_reg_t mmu_grp_cfg_regs[2] = { 1398 HPIPE0_OVR_SUB_GRP_CFGr, HPIPE1_OVR_SUB_GRP_CFGr 1399 }; 1400 1401 static const soc_reg_t idb_grp_ovs_regs[TRIDENT3_TDM_PIPES_PER_DEV][2][6] = { 1402 { 1403 {IS_HPIPE0_OVR_SUB_GRP0_TBL_PIPE0r, IS_HPIPE0_OVR_SUB_GRP1_TBL_PIPE0r, 1404 IS_HPIPE0_OVR_SUB_GRP2_TBL_PIPE0r, IS_HPIPE0_OVR_SUB_GRP3_TBL_PIPE0r, 1405 IS_HPIPE0_OVR_SUB_GRP4_TBL_PIPE0r, IS_HPIPE0_OVR_SUB_GRP5_TBL_PIPE0r }, 1406 {IS_HPIPE1_OVR_SUB_GRP0_TBL_PIPE0r, IS_HPIPE1_OVR_SUB_GRP1_TBL_PIPE0r, 1407 IS_HPIPE1_OVR_SUB_GRP2_TBL_PIPE0r, IS_HPIPE1_OVR_SUB_GRP3_TBL_PIPE0r, 1408 IS_HPIPE1_OVR_SUB_GRP4_TBL_PIPE0r, IS_HPIPE1_OVR_SUB_GRP5_TBL_PIPE0r } 1409 }, 1410 { 1411 {IS_HPIPE0_OVR_SUB_GRP0_TBL_PIPE1r, IS_HPIPE0_OVR_SUB_GRP1_TBL_PIPE1r, 1412 IS_HPIPE0_OVR_SUB_GRP2_TBL_PIPE1r, IS_HPIPE0_OVR_SUB_GRP3_TBL_PIPE1r, 1413 IS_HPIPE0_OVR_SUB_GRP4_TBL_PIPE1r, IS_HPIPE0_OVR_SUB_GRP5_TBL_PIPE1r }, 1414 {IS_HPIPE1_OVR_SUB_GRP0_TBL_PIPE1r, IS_HPIPE1_OVR_SUB_GRP1_TBL_PIPE1r, 1415 IS_HPIPE1_OVR_SUB_GRP2_TBL_PIPE1r, IS_HPIPE1_OVR_SUB_GRP3_TBL_PIPE1r, 1416 IS_HPIPE1_OVR_SUB_GRP4_TBL_PIPE1r, IS_HPIPE1_OVR_SUB_GRP5_TBL_PIPE1r } 1417 } 1418 }; 1419 1420 static const soc_reg_t mmu_grp_ovs_regs[2][6] = { 1421 {HPIPE0_OVR_SUB_GRP0_TBLr, HPIPE0_OVR_SUB_GRP1_TBLr, 1422 HPIPE0_OVR_SUB_GRP2_TBLr, HPIPE0_OVR_SUB_GRP3_TBLr, 1423 HPIPE0_OVR_SUB_GRP4_TBLr, HPIPE0_OVR_SUB_GRP5_TBLr }, 1424 {HPIPE1_OVR_SUB_GRP0_TBLr, HPIPE1_OVR_SUB_GRP1_TBLr, 1425 HPIPE1_OVR_SUB_GRP2_TBLr, HPIPE1_OVR_SUB_GRP3_TBLr, 1426 HPIPE1_OVR_SUB_GRP4_TBLr, HPIPE1_OVR_SUB_GRP5_TBLr } 1427 }; 1428 1429 static const soc_reg_t idb_pblk_cal_regs[TRIDENT3_TDM_PIPES_PER_DEV][2][8] = { 1430 { 1431 {IS_HPIPE0_PBLK0_CALENDAR_PIPE0r, IS_HPIPE0_PBLK1_CALENDAR_PIPE0r, 1432 IS_HPIPE0_PBLK2_CALENDAR_PIPE0r, IS_HPIPE0_PBLK3_CALENDAR_PIPE0r, 1433 IS_HPIPE0_PBLK4_CALENDAR_PIPE0r, IS_HPIPE0_PBLK5_CALENDAR_PIPE0r, 1434 IS_HPIPE0_PBLK6_CALENDAR_PIPE0r, IS_HPIPE0_PBLK7_CALENDAR_PIPE0r }, 1435 {IS_HPIPE1_PBLK0_CALENDAR_PIPE0r, IS_HPIPE1_PBLK1_CALENDAR_PIPE0r, 1436 IS_HPIPE1_PBLK2_CALENDAR_PIPE0r, IS_HPIPE1_PBLK3_CALENDAR_PIPE0r, 1437 IS_HPIPE1_PBLK4_CALENDAR_PIPE0r, IS_HPIPE1_PBLK5_CALENDAR_PIPE0r, 1438 IS_HPIPE1_PBLK6_CALENDAR_PIPE0r, IS_HPIPE1_PBLK7_CALENDAR_PIPE0r } 1439 }, 1440 { 1441 {IS_HPIPE0_PBLK0_CALENDAR_PIPE1r, IS_HPIPE0_PBLK1_CALENDAR_PIPE1r, 1442 IS_HPIPE0_PBLK2_CALENDAR_PIPE1r, IS_HPIPE0_PBLK3_CALENDAR_PIPE1r, 1443 IS_HPIPE0_PBLK4_CALENDAR_PIPE1r, IS_HPIPE0_PBLK5_CALENDAR_PIPE1r, 1444 IS_HPIPE0_PBLK6_CALENDAR_PIPE1r, IS_HPIPE0_PBLK7_CALENDAR_PIPE1r }, 1445 {IS_HPIPE1_PBLK0_CALENDAR_PIPE1r, IS_HPIPE1_PBLK1_CALENDAR_PIPE1r, 1446 IS_HPIPE1_PBLK2_CALENDAR_PIPE1r, IS_HPIPE1_PBLK3_CALENDAR_PIPE1r, 1447 IS_HPIPE1_PBLK4_CALENDAR_PIPE1r, IS_HPIPE1_PBLK5_CALENDAR_PIPE1r, 1448 IS_HPIPE1_PBLK6_CALENDAR_PIPE1r, IS_HPIPE1_PBLK7_CALENDAR_PIPE1r } 1449 } 1450 }; 1451 1452 static const soc_reg_t mmu_pblk_cal_regs[2][8] = { 1453 {HPIPE0_PBLK0_CALENDARr, HPIPE0_PBLK1_CALENDARr, 1454 HPIPE0_PBLK2_CALENDARr, HPIPE0_PBLK3_CALENDARr, 1455 HPIPE0_PBLK4_CALENDARr, HPIPE0_PBLK5_CALENDARr, 1456 HPIPE0_PBLK6_CALENDARr, HPIPE0_PBLK7_CALENDARr }, 1457 {HPIPE1_PBLK0_CALENDARr, HPIPE1_PBLK1_CALENDARr, 1458 HPIPE1_PBLK2_CALENDARr, HPIPE1_PBLK3_CALENDARr, 1459 HPIPE1_PBLK4_CALENDARr, HPIPE1_PBLK5_CALENDARr, 1460 HPIPE1_PBLK6_CALENDARr, HPIPE1_PBLK7_CALENDARr } 1461 }; 1462 1463 static int pblk_slots[SOC_TD3_PORT_RATIO_COUNT][7] = { 1464 { 0, -1, 0, 0, -1, 0, -1 }, /* SOC_TD3_PORT_RATIO_SINGLE */ 1465 { 0, -1, 2, 0, -1, 2, -1 }, /* SOC_TD3_PORT_RATIO_DUAL_1_1 */ 1466 { 0, 0, 2, 0, 0, 2, -1 }, /* SOC_TD3_PORT_RATIO_DUAL_2_1 */ 1467 { 0, 2, 2, 0, 2, 2, -1 }, /* SOC_TD3_PORT_RATIO_DUAL_1_2 */ 1468 { 0, -1, 2, 0, -1, 3, -1 }, /* SOC_TD3_PORT_RATIO_TRI_023_2_1_1 */ 1469 { 0, 0, 2, 0, 0, 3, -1 }, /* SOC_TD3_PORT_RATIO_TRI_023_4_1_1 */ 1470 { 0, -1, 2, 1, -1, 2, -1 }, /* SOC_TD3_PORT_RATIO_TRI_012_1_1_2 */ 1471 { 0, 2, 2, 1, 2, 2, -1 }, /* SOC_TD3_PORT_RATIO_TRI_012_1_1_4 */ 1472 { 0, -1, 2, 1, -1, 3, -1 } /* SOC_TD3_PORT_RATIO_QUAD */ 1473 }; 1474 1475 _soc_td3_tdm_get_pipe_map(unit, sch_info, &pipe_map); 1476 _soc_td3_tdm_get_ovs_pipe_map(unit, sch_info, &ovs_pipe_map); 1477 1478 /* OVS tables */ 1479 for (pipe = 0; pipe < TRIDENT3_TDM_PIPES_PER_DEV; pipe++) { 1480 if (!(ovs_pipe_map & (1 << pipe))) { 1481 continue; 1482 } 1483 inst = pipe | SOC_REG_ADDR_INSTANCE_MASK; 1484 for (hpipe = 0; hpipe < TRIDENT3_TDM_HPIPES_PER_PIPE; hpipe++) { 1485 for (group = 0; group < TRIDENT3_TDM_OVS_GROUPS_PER_HPIPE; group++) { 1486 for (slot = 0; slot < TRIDENT3_TDM_OVS_GROUP_LENGTH; slot++) { 1487 phy_port = sch_info->tdm_ingress_schedule_pipe[ 1488 pipe].tdm_schedule_slice[hpipe].oversub_schedule[group][slot]; 1489 /* PORT_NUMf restricts port numbering within [0-31] & 0x3f 1490 * HPIPE0 port 0-31 maps to mmu/idb port 0-31 1491 * HPIPE1 port 0-31 maps to mmu/idb port 32-63 1492 * PHY_PORT_IDf restricts port block id within [0-7] 1493 */ 1494 if (phy_port > TD3_NUM_PHY_PORTS) { 1495 idb_port = 0x3f; 1496 mmu_port = 0x3f; 1497 id = 0x7; 1498 } else { 1499 port = sch_info->in_port_map.port_p2l_mapping[phy_port]; 1500 idb_port = sch_info->in_port_map.port_l2i_mapping[ 1501 port] & 0x1f; 1502 mmu_port = sch_info->in_port_map.port_p2m_mapping[ 1503 phy_port] & 0x1f; 1504 id = sch_info->out_port_map.port_p2PBLK_inst_mapping[ 1505 phy_port] & 0x7; 1506 } 1507 /* IDB OverSub Groups */ 1508 if (set_idb == 1) { 1509 rval = 0; 1510 reg = idb_grp_ovs_regs[pipe][hpipe][group]; 1511 soc_reg_field_set(unit, reg, &rval, PHY_PORT_IDf, id); 1512 soc_reg_field_set(unit, reg, &rval, PORT_NUMf, idb_port); 1513 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, reg, REG_PORT_ANY, 1514 slot, rval)); 1515 } 1516 /* MMU OverSub Groups */ 1517 if (set_mmu == 1) { 1518 rval = 0; 1519 reg = mmu_grp_ovs_regs[hpipe][group]; 1520 soc_reg_field_set(unit, reg, &rval, PHY_PORT_IDf, id); 1521 soc_reg_field_set(unit, reg, &rval, PORT_NUMf, mmu_port); 1522 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, reg, inst, 1523 slot, rval)); 1524 } 1525 } 1526 1527 /* Handle the case where the first element in the group 1528 * is invalid but other valid ports exist in the group. 1529 */ 1530 for (slot = 0; slot < TRIDENT3_TDM_OVS_GROUP_LENGTH; slot++) { 1531 phy_port = sch_info->tdm_ingress_schedule_pipe[ 1532 pipe].tdm_schedule_slice[hpipe].oversub_schedule[group][slot]; 1533 if (phy_port < TD3_NUM_EXT_PORTS) { 1534 break; 1535 } 1536 } 1537 1538 /* No valid ports found, skip group */ 1539 if (TRIDENT3_TDM_OVS_GROUP_LENGTH == slot) { 1540 port_speed_class = 0; 1541 port_same_spacing = 0; 1542 port_sister_spacing = 0; 1543 } else { 1544 port = sch_info->in_port_map.port_p2l_mapping[phy_port]; 1545 prev_or_new = 1; 1546 soc_td3_tdm_get_log_port_speed(unit, sch_info, port, 1547 prev_or_new, &l_speed, &l_num_lanes); 1548 speed_max = 25000 * l_num_lanes; 1549 if (speed_max > l_speed) speed_max = l_speed; 1550 1551 port_speed_class = 1552 _soc_td3_tdm_get_speed_ovs_class(unit, speed_max); 1553 port_same_spacing = 1554 _soc_td3_tdm_get_same_port_spacing_e(unit, speed_max); 1555 port_sister_spacing = 4; 1556 } 1557 if (set_idb == 1) { 1558 rval = 0; 1559 reg = idb_grp_cfg_regs[pipe][hpipe]; 1560 soc_reg_field_set(unit, reg, &rval, SAME_SPACINGf, 8); /* on ingress, all ports have same spacing */ 1561 soc_reg_field_set(unit, reg, &rval, SISTER_SPACINGf, 1562 port_sister_spacing); 1563 soc_reg_field_set(unit, reg, &rval, SPEEDf, 1564 port_speed_class); 1565 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, reg, REG_PORT_ANY, 1566 group, rval)); 1567 } 1568 if (set_mmu == 1) { 1569 rval = 0; 1570 reg = mmu_grp_cfg_regs[hpipe]; 1571 soc_reg_field_set(unit, reg, &rval, SAME_SPACINGf, 1572 port_same_spacing); 1573 soc_reg_field_set(unit, reg, &rval, SISTER_SPACINGf, 1574 port_sister_spacing); 1575 soc_reg_field_set(unit, reg, &rval, SPEEDf, 1576 port_speed_class); 1577 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, reg, inst, 1578 group, rval)); 1579 } 1580 } 1581 } 1582 } 1583 1584 /* 16 Port-blocks are supported, with each instance of Oversubscription 1585 * Cell Scheduler supports up to 8 Portblocks. */ 1586 1587 /* First get pblk_cal_idx to pm_num mapping from 1588 * pm_num to pblk_cal_idx 1589 * and **oversub_schedule 1590 */ 1591 /* sal_memset(pblks, -1, sizeof(pblks)); */ 1592 sal_memset(pblks, -1, sizeof(int) * TRIDENT3_TDM_PIPES_PER_DEV * 2 * 1593 TRIDENT3_TDM_PBLKS_PER_HPIPE); 1594 for (pipe = 0; pipe < TRIDENT3_TDM_PIPES_PER_DEV; pipe++) { 1595 if (!(ovs_pipe_map & (1 << pipe))) { 1596 continue; 1597 } 1598 for (hpipe = 0; hpipe < TRIDENT3_TDM_HPIPES_PER_PIPE; hpipe++) { 1599 for (group = 0; group < TRIDENT3_TDM_OVS_GROUPS_PER_HPIPE; group++) { 1600 for (slot = 0; slot < TRIDENT3_TDM_OVS_GROUP_LENGTH; slot++) { 1601 phy_port = sch_info->tdm_ingress_schedule_pipe[ 1602 pipe].tdm_schedule_slice[hpipe].oversub_schedule[group][slot]; 1603 if (phy_port < TD3_NUM_EXT_PORTS) { 1604 pm_num = (phy_port - 1) / TRIDENT3_TDM_PORTS_PER_PBLK; 1605 pblk_cal_idx = 1606 sch_info->out_port_map.port_p2PBLK_inst_mapping[phy_port]; 1607 if (pblk_cal_idx >= 0 && 1608 pblk_cal_idx < TRIDENT3_TDM_PBLKS_PER_HPIPE) { 1609 pblks[pipe][hpipe][pblk_cal_idx] = pm_num; 1610 } else { 1611 return SOC_E_FAIL; /* invalid mapping */ 1612 } 1613 } 1614 } 1615 } 1616 } 1617 } 1618 1619 /* Configure PBLKs */ 1620 for (pipe = 0; pipe < TRIDENT3_TDM_PIPES_PER_DEV; pipe++) { 1621 if (!(ovs_pipe_map & (1 << pipe))) { 1622 continue; 1623 } 1624 1625 inst = pipe | SOC_REG_ADDR_INSTANCE_MASK; 1626 for (hpipe = 0; hpipe < TRIDENT3_TDM_HPIPES_PER_PIPE; hpipe++) { 1627 for (pblk_cal_idx = 0; pblk_cal_idx < TRIDENT3_TDM_PBLKS_PER_HPIPE; 1628 pblk_cal_idx++) { 1629 pm_num = pblks[pipe][hpipe][pblk_cal_idx]; 1630 phy_port_base = 1 + (pm_num * TRIDENT3_TDM_PORTS_PER_PBLK); 1631 /* Get port ratio for this Port Macro */ 1632 soc_td3_tdm_get_port_ratio(unit, sch_info, pm_num, &mode, 1); 1633 reg = idb_pblk_cal_regs[pipe][hpipe][pblk_cal_idx]; 1634 reg1 = mmu_pblk_cal_regs[hpipe][pblk_cal_idx]; 1635 /* Write PBLK regs 1636 * Only first 6 out of 7 slots could be valid 1637 */ 1638 if ((pm_num < 0) || (pm_num > TRIDENT3_TDM_PBLKS_PER_DEV)) { 1639 /* To speed-up init this branch could be skipped */ 1640 for (slot = 0; slot < 6; slot++) { 1641 rval = 0; 1642 rval1 = 0; 1643 if (set_idb == 1) { 1644 soc_reg_field_set(unit, reg, &rval, PORT_NUMf, 1645 0x3f); 1646 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, reg, 1647 REG_PORT_ANY, slot, rval)); 1648 } 1649 if (set_mmu == 1) { 1650 soc_reg_field_set(unit, reg1, &rval1, PORT_NUMf, 1651 0x3f); 1652 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, reg1, 1653 inst, slot, rval1)); 1654 } 1655 } 1656 } else { 1657 for (slot = 0; slot < 6; slot++) { 1658 rval = 0; 1659 rval1 = 0; 1660 lane = pblk_slots[mode][slot]; 1661 if (lane == -1) { 1662 pblk_valid = 0; 1663 idb_port = 0x3f; 1664 mmu_port = 0x3f; 1665 pblk_spacing = 0; /* same spacing */ 1666 } else { 1667 pblk_valid = 1; 1668 port = sch_info->in_port_map.port_p2l_mapping[ 1669 phy_port_base + lane]; 1670 idb_port = sch_info->in_port_map.port_l2i_mapping[ 1671 port] & 0x1f; 1672 mmu_port = sch_info->in_port_map.port_p2m_mapping[ 1673 phy_port_base + lane] & 0x1f; 1674 1675 prev_or_new = 1; 1676 soc_td3_tdm_get_log_port_speed(unit, sch_info, 1677 port, prev_or_new, &l_speed, &l_num_lanes); 1678 speed_max = 25000 * l_num_lanes; 1679 if (speed_max > l_speed) speed_max = l_speed; 1680 1681 port_speed_class = 1682 _soc_td3_tdm_get_speed_ovs_class(unit, 1683 speed_max); 1684 pblk_spacing = 1685 _soc_td3_tdm_get_same_port_spacing_e(unit, 1686 speed_max); 1687 } 1688 1689 soc_reg_field_set(unit, reg, &rval, VALIDf, 1690 pblk_valid); 1691 soc_reg_field_set(unit, reg, &rval, SPACINGf, 1692 8); 1693 soc_reg_field_set(unit, reg, &rval, PORT_NUMf, 1694 idb_port); 1695 1696 soc_reg_field_set(unit, reg1, &rval1, VALIDf, 1697 pblk_valid); 1698 soc_reg_field_set(unit, reg1, &rval1, SPACINGf, 1699 pblk_spacing); 1700 soc_reg_field_set(unit, reg1, &rval1, PORT_NUMf, 1701 mmu_port); 1702 if (set_idb == 1) { 1703 SOC_IF_ERROR_RETURN 1704 (soc_reg32_set(unit, reg, REG_PORT_ANY, 1705 slot, rval)); 1706 } 1707 if (set_mmu == 1) { 1708 SOC_IF_ERROR_RETURN 1709 (soc_reg32_set(unit, reg1, inst, 1710 slot, rval1)); 1711 } 1712 } 1713 } 1714 } 1715 } 1716 } 1717 1718 return SOC_E_NONE; 1719 } 1720 1721 1722 /*! @fn int _soc_td3_tdm_set_ovs_group( 1723 int unit, 1724 soc_port_schedule_state_t *sch_info) 1725 @param unit Chip unit number. 1726 @param sch_info Pointer to a soc_port_schedule_state_t struct variable. 1727 @brief API to initialize the TD3 MMU & IDB OVS tables. 1728 Regs/Mems configured: IDB HPIPE0/1_OVR_SUB_GRP_CFG 1729 HPIPE0/1_OVR_SUB_GRP_CFG 1730 PBLK<n>_CALENDAR 1731 */ 1732 int 1733 _soc_td3_tdm_set_ovs_group(int unit, soc_port_schedule_state_t *sch_info) 1734 { 1735 return (_soc_td3_tdm_set_ovs_group_sel(unit, sch_info, 1, 1)); 1736 } 1737 1738 1739 /*! @fn int _soc_td3_tdm_set_mmu_calendar( 1740 int unit, 1741 soc_port_schedule_state_t *sch_info) 1742 @param unit Chip unit number. 1743 @param sch_info Pointer to a soc_port_schedule_state_t struct variable. 1744 @brief API to initialize the TD3 MMU main calendar. 1745 Regs/Mems configured: MMU TDM_CALENDAR 1746 TDM_CONFIG 1747 */ 1748 int 1749 _soc_td3_tdm_set_mmu_calendar(int unit, soc_port_schedule_state_t *sch_info) 1750 { 1751 uint32 pipe_map; 1752 uint32 cal_len; 1753 soc_mem_t mem; 1754 soc_reg_t reg; 1755 soc_field_t cal_end_field; 1756 int pipe, slot, id, length, calendar_id; 1757 int phy_port, mmu_port, inst; 1758 uint32 rval; 1759 uint32 memfld; 1760 uint32 entry[SOC_MAX_MEM_WORDS]; 1761 uint32 mem_indx; 1762 static const soc_mem_t calendar_mems[] = { 1763 TDM_CALENDAR0_PIPE0m, 1764 TDM_CALENDAR0_PIPE1m, 1765 TDM_CALENDAR1_PIPE0m, 1766 TDM_CALENDAR1_PIPE1m 1767 }; 1768 static const soc_field_t calendar_end_fields[] = { 1769 CAL0_ENDf, CAL1_ENDf 1770 }; 1771 1772 _soc_td3_tdm_get_pipe_map(unit, sch_info, &pipe_map); 1773 sal_memset(entry, 0, sizeof(uint32) * soc_mem_entry_words(unit, 1774 TDM_CALENDAR0_PIPE0m)); 1775 for (pipe = 0; pipe < TRIDENT3_TDM_PIPES_PER_DEV; pipe++) { 1776 if (!(pipe_map & (1 << pipe))) { 1777 continue; 1778 } 1779 1780 /* Determine calendar_id: 0 or 1 */ 1781 reg = TDM_CONFIGr; 1782 inst = pipe | SOC_REG_ADDR_INSTANCE_MASK; 1783 if (sch_info->is_flexport == 1) { /* choose "the other one" */ 1784 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, reg, inst, 0, &rval)); 1785 calendar_id = soc_reg_field_get(unit, reg, rval, CURR_CALf) ^ 1; 1786 } else { 1787 calendar_id = 0; /* At init use calendar_id=0 */ 1788 rval = 0; 1789 } 1790 mem = calendar_mems[(calendar_id * TRIDENT3_TDM_PIPES_PER_DEV) + pipe]; 1791 cal_end_field = calendar_end_fields[calendar_id]; 1792 1793 /* TDM Calendar is always taken from slice 0 */ 1794 cal_len = sch_info->tdm_egress_schedule_pipe[ 1795 pipe].tdm_schedule_slice[0].cal_len; 1796 for (length = cal_len; length > 0; length--) { 1797 if (sch_info->tdm_egress_schedule_pipe[pipe].tdm_schedule_slice[ 1798 0].linerate_schedule[length - 1] != TD3_NUM_EXT_PORTS) { 1799 break; 1800 } 1801 } 1802 for (slot = 0; slot < length; slot += 2) { 1803 /* EVEN */ 1804 phy_port = sch_info->tdm_egress_schedule_pipe[ 1805 pipe].tdm_schedule_slice[0].linerate_schedule[slot]; 1806 if (phy_port == TD3_OVSB_TOKEN) { 1807 mmu_port = TRIDENT3_TDM_MMU_OVSB_TOKEN; 1808 } else if (phy_port == TD3_IDL1_TOKEN) { 1809 mmu_port = TRIDENT3_TDM_MMU_PURG_TOKEN; 1810 } else if (phy_port == TD3_IDL2_TOKEN) { 1811 mmu_port = TRIDENT3_TDM_MMU_UNUSED_TOKEN; 1812 } else if (phy_port == TD3_NULL_TOKEN) { 1813 mmu_port = TRIDENT3_TDM_MMU_NULL_TOKEN; 1814 } else if (phy_port >= TD3_NUM_EXT_PORTS) { 1815 mmu_port = TRIDENT3_TDM_MMU_UNUSED_TOKEN; 1816 } else if (phy_port == TD3_MGM1_TOKEN) { 1817 /* TDM code always allocates slots for management port. 1818 * If mgmt ports are omitted from config, this mapping 1819 * is not set up. 1820 */ 1821 mmu_port = TRIDENT3_TDM_MMU_MGMT1_TOKEN; 1822 } else { 1823 /* [0,69] && 127 */ 1824 mmu_port = sch_info->out_port_map.port_p2m_mapping[ 1825 phy_port] & 0x7f; 1826 } 1827 if (mmu_port > 63) { 1828 id = 0xf; 1829 } else { 1830 id = (phy_port - 1) / TRIDENT3_TDM_PORTS_PER_PBLK; 1831 } 1832 memfld = mmu_port & 0x7f; 1833 soc_mem_field_set(unit, mem, entry, PORT_NUM_EVENf, &memfld); 1834 memfld = id & 0xf; 1835 soc_mem_field_set(unit, mem, entry, PHY_PORT_ID_EVENf, &memfld); 1836 /* ODD */ 1837 phy_port = sch_info->tdm_egress_schedule_pipe[ 1838 pipe].tdm_schedule_slice[0].linerate_schedule[slot + 1]; 1839 if (phy_port == TD3_OVSB_TOKEN) { 1840 mmu_port = TRIDENT3_TDM_MMU_OVSB_TOKEN; 1841 } else if (phy_port == TD3_IDL1_TOKEN) { 1842 mmu_port = TRIDENT3_TDM_MMU_PURG_TOKEN; 1843 } else if (phy_port == TD3_IDL2_TOKEN) { 1844 mmu_port = TRIDENT3_TDM_MMU_UNUSED_TOKEN; 1845 } else if (phy_port == TD3_NULL_TOKEN) { 1846 mmu_port = TRIDENT3_TDM_MMU_NULL_TOKEN; 1847 } else if (phy_port >= TD3_NUM_EXT_PORTS) { 1848 mmu_port = TRIDENT3_TDM_MMU_UNUSED_TOKEN; 1849 } else if (phy_port == TD3_MGM1_TOKEN) { 1850 /* TDM code always allocates slots for management port. 1851 * If mgmt ports are omitted from config, this mapping 1852 * is not set up. 1853 */ 1854 mmu_port = TRIDENT3_TDM_MMU_MGMT1_TOKEN; 1855 } else { 1856 /* [0,69] && 127 */ 1857 mmu_port = sch_info->out_port_map.port_p2m_mapping[ 1858 phy_port] & 0x7f; 1859 } 1860 if (mmu_port > 63) { 1861 id = 0xf; 1862 } else { 1863 id = (phy_port - 1) / TRIDENT3_TDM_PORTS_PER_PBLK; 1864 } 1865 memfld = mmu_port & 0x7f; 1866 soc_mem_field_set(unit, mem, entry, PORT_NUM_ODDf, &memfld); 1867 memfld = id & 0xf; 1868 soc_mem_field_set(unit, mem, entry, PHY_PORT_ID_ODDf, &memfld); 1869 /* Memory entry */ 1870 mem_indx = slot / 2; 1871 SOC_IF_ERROR_RETURN 1872 (soc_mem_write(unit, mem, MEM_BLOCK_ALL, mem_indx, entry)); 1873 } 1874 1875 /* set for 2nd management port */ 1876 if (_soc_td3_tdm_check_2nd_mgmt_enable(unit, sch_info) == 1 && 1877 pipe == (TRIDENT3_TDM_PIPES_PER_DEV - 1)) { 1878 soc_reg_field_set(unit, reg, &rval, MGMT_2ND_PORT_ENABLEf, 1); 1879 } 1880 1881 soc_reg_field_set(unit, reg, &rval, cal_end_field, length-1); 1882 soc_reg_field_set(unit, reg, &rval, CURR_CALf, calendar_id); 1883 soc_reg_field_set(unit, reg, &rval, ENABLEf, 1); 1884 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, reg, inst, 0, rval)); 1885 } 1886 1887 return SOC_E_NONE; 1888 } 1889 1890 1891 /*! @fn int _soc_td3_tdm_set_mmu_hsp( 1892 int unit, 1893 soc_port_schedule_state_t *sch_info) 1894 @param unit Chip unit number. 1895 @param sch_info Pointer to a soc_port_schedule_state_t struct variable. 1896 @brief API to initialize the TD3 MMU HSP. 1897 Regs/Mems configured: TDM_HSP_PIPE 1898 */ 1899 int 1900 _soc_td3_tdm_set_mmu_hsp(int unit, 1901 soc_port_schedule_state_t *sch_info) 1902 { 1903 soc_reg_t reg; 1904 uint32 pipe_map; 1905 int pipe, hpipe, inst; 1906 int port, mmu_port, phy_port; 1907 uint32 port_map[TRIDENT3_TDM_PIPES_PER_DEV][2]; 1908 uint32 rval = 0; 1909 int l_speed = 0, l_num_lanes = 0, prev_or_new = 0; 1910 1911 _soc_td3_tdm_get_pipe_map(unit, sch_info, &pipe_map); 1912 1913 for (pipe = 0; pipe < TRIDENT3_TDM_PIPES_PER_DEV; pipe++) { 1914 port_map[pipe][0] = 0; 1915 port_map[pipe][1] = 0; 1916 } 1917 1918 for (port=0; port<TRIDENT3_TDM_PHY_PORTS_PER_DEV; port++) { 1919 if (sch_info->out_port_map.log_port_speed[port] > 0) { 1920 soc_td3_tdm_get_log_port_speed(unit, sch_info, port, 1921 prev_or_new, &l_speed, &l_num_lanes); 1922 if (_soc_td3_tdm_check_is_hsp_port_e(unit, l_speed) == 1) { 1923 phy_port = sch_info->out_port_map.port_l2p_mapping[port]; 1924 if ((phy_port >= 1) && (phy_port <= TRIDENT3_TDM_GPORTS_PER_DEV)) { 1925 pipe = (phy_port - 1) / TRIDENT3_TDM_GPORTS_PER_PIPE; 1926 hpipe = ((phy_port - 1) & 0x3f) / 1927 TRIDENT3_TDM_GPORTS_PER_HPIPE; 1928 mmu_port = sch_info->out_port_map.port_p2m_mapping[ 1929 phy_port] & 0x1f; 1930 if (pipe < TRIDENT3_TDM_PIPES_PER_DEV && hpipe < 2) { 1931 port_map[pipe][hpipe] |= 1 << mmu_port; 1932 } 1933 } 1934 } 1935 } 1936 } 1937 1938 for (pipe = 0; pipe < TRIDENT3_TDM_PIPES_PER_DEV; pipe++) { 1939 if (!(pipe_map & (1 << pipe))) { 1940 continue; 1941 } 1942 inst = pipe | SOC_REG_ADDR_INSTANCE_MASK; 1943 1944 reg = TDM_HSP_0r; 1945 soc_reg_field_set(unit, reg, &rval, PORT_BMPf, port_map[pipe][0]); 1946 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, reg, inst, 0, rval)); 1947 1948 reg = TDM_HSP_1r; 1949 soc_reg_field_set(unit, reg, &rval, PORT_BMPf, port_map[pipe][1]); 1950 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, reg, inst, 0, rval)); 1951 } 1952 1953 return SOC_E_NONE; 1954 } 1955 1956 1957 /*! @fn int _soc_td3_tdm_set_mmu_opportunistic( 1958 int unit, 1959 soc_port_schedule_state_t *sch_info, 1960 int cpu_op_en, 1961 int lb_opp_en, 1962 int opp1_port_en, 1963 int opp2_port_en, 1964 int opp_ovr_sub_en) 1965 @param unit Chip unit number. 1966 @param sch_info Pointer to a soc_port_schedule_state_t struct variable. 1967 @param cpu_op_en 1968 @param lb_opp_en 1969 @param opp1_port_en 1970 @param opp2_port_en 1971 @param opp_ovr_sub_en 1972 @brief API to initialize the TD3 MMU Opportunistic related registers 1973 Regs/Mems configured: CPU_LB_OPP_CFG 1974 OPP_SCHED_CFG 1975 */ 1976 int 1977 _soc_td3_tdm_set_mmu_opportunistic(int unit, 1978 soc_port_schedule_state_t *sch_info, 1979 int cpu_op_en, 1980 int lb_opp_en, 1981 int opp1_port_en, 1982 int opp2_port_en, 1983 int opp_ovr_sub_en) 1984 { 1985 uint32 pipe_map; 1986 soc_reg_t reg; 1987 int pipe; 1988 int inst; 1989 uint32 rval; 1990 1991 _soc_td3_tdm_get_pipe_map(unit, sch_info, &pipe_map); 1992 1993 for (pipe = 0; pipe < TRIDENT3_TDM_PIPES_PER_DEV; pipe++) { 1994 if (!(pipe_map & (1 << pipe))) { 1995 continue; 1996 } 1997 1998 inst = pipe | SOC_REG_ADDR_INSTANCE_MASK; 1999 2000 reg = CPU_LB_OPP_CFGr; 2001 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, reg, inst, 0, &rval)); 2002 soc_reg_field_set(unit, reg, &rval, CPU_OPP_ENf, 2003 (cpu_op_en == 1) ? 1 : 0); 2004 soc_reg_field_set(unit, reg, &rval, LB_OPP_ENf, 2005 (lb_opp_en == 1) ? 1 : 0); 2006 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, reg, inst, 0, rval)); 2007 2008 reg = OPP_SCHED_CFGr; 2009 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, reg, inst, 0, &rval)); 2010 soc_reg_field_set(unit, reg, &rval, OPP1_PORT_ENf, 2011 (opp1_port_en == 1) ? 1 : 0); 2012 soc_reg_field_set(unit, reg, &rval, OPP1_SPACINGf, 6); 2013 soc_reg_field_set(unit, reg, &rval, OPP2_PORT_ENf, 2014 (opp2_port_en == 1) ? 1 : 0); 2015 soc_reg_field_set(unit, reg, &rval, OPP2_SPACINGf, 0); 2016 soc_reg_field_set(unit, reg, &rval, OPP_OVR_SUB_ENf, 2017 (opp_ovr_sub_en == 1) ? 1 : 0); 2018 soc_reg_field_set(unit, reg, &rval, OPP_STRICT_PRIf, 0); 2019 soc_reg_field_set(unit, reg, &rval, DISABLE_PORT_NUMf, 67); 2020 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, reg, inst, 0, rval)); 2021 } 2022 2023 return SOC_E_NONE; 2024 } 2025 2026 2027 /*! @fn int soc_td3_tdm_init( 2028 int unit, 2029 soc_port_schedule_state_t *sch_info) 2030 @param unit Chip unit number. 2031 @param sch_info Pointer to a soc_port_schedule_state_t struct variable. 2032 @brief Main API for TDM init 2033 */ 2034 int soc_td3_tdm_init(int unit, soc_port_schedule_state_t *sch_info) 2035 { 2036 SOC_IF_ERROR_RETURN(_soc_td3_tdm_calculation(unit, sch_info)); 2037 2038 SOC_IF_ERROR_RETURN(_soc_td3_tdm_set_idb_calendar(unit, sch_info)); 2039 SOC_IF_ERROR_RETURN(_soc_td3_tdm_set_idb_hsp(unit, sch_info)); 2040 SOC_IF_ERROR_RETURN(_soc_td3_tdm_set_idb_pkt_calendar(unit, sch_info)); 2041 SOC_IF_ERROR_RETURN(_soc_td3_tdm_set_idb_ppe_credit(unit, sch_info, 2042 16, 9, 16, 9)); 2043 /* IDB opp1_port_en should always be 1 to enable sbus access to the rest of IPIPE*/ 2044 SOC_IF_ERROR_RETURN(_soc_td3_tdm_set_idb_opportunistic(unit, sch_info, 2045 1, 1, 1, 1, 1)); 2046 2047 SOC_IF_ERROR_RETURN(_soc_td3_tdm_set_ovs_group(unit, sch_info)); 2048 SOC_IF_ERROR_RETURN(_soc_td3_tdm_set_mmu_calendar(unit, sch_info)); 2049 SOC_IF_ERROR_RETURN(_soc_td3_tdm_set_mmu_hsp(unit, sch_info)); 2050 SOC_IF_ERROR_RETURN(_soc_td3_tdm_set_mmu_opportunistic(unit, sch_info, 2051 1, 1, 1, 1, 1)); 2052 2053 return SOC_E_NONE; 2054 } 2055 2056 /*! @fn int soc_trident3_port_speed_higig2eth(int speed) 2057 * @param int speed 2058 * @brief Map port speed to ETH bitrates 2059 */ 2060 static int 2061 soc_trident3_port_speed_higig2eth(int speed) 2062 { 2063 switch (speed) { 2064 case 11000: 2065 /* 10G */ 2066 return 10000; 2067 case 21000: 2068 /* 20G */ 2069 return 20000; 2070 case 27000: 2071 /* 25G */ 2072 return 25000; 2073 case 42000: 2074 /* 40G */ 2075 return 40000; 2076 case 53000: 2077 /* 50G */ 2078 return 50000; 2079 case 106000: 2080 /* 100G */ 2081 return 100000; 2082 default: 2083 return speed; 2084 } 2085 } 2086 2087 /*! @fn void soc_trident3_port_schedule_speed_remap(int unit, 2088 * soc_port_schedule_state_t *port_schedule_state) 2089 * @param unit Chip unit number. 2090 * @param port_schedule_state Pointer to a soc_port_schedule_state_t struct 2091 * variable. 2092 * @brief API to remap speeds to ETH bitrates 2093 */ 2094 void 2095 soc_trident3_port_schedule_speed_remap( 2096 int unit, 2097 soc_port_schedule_state_t *port_schedule_state) 2098 { 2099 int i, port; 2100 2101 /* Speed remap for in_port_map*/ 2102 for (port=0; port < SOC_MAX_NUM_PORTS; port++) { 2103 port_schedule_state->in_port_map.log_port_speed[port] = 2104 soc_trident3_port_speed_higig2eth( 2105 port_schedule_state->in_port_map.log_port_speed[port]); 2106 } 2107 2108 if (port_schedule_state->is_flexport == 1) { 2109 /* Speed remap for out_port_map*/ 2110 for (port=0; port < SOC_MAX_NUM_PORTS; port++) { 2111 port_schedule_state->out_port_map.log_port_speed[port] = 2112 soc_trident3_port_speed_higig2eth( 2113 port_schedule_state->out_port_map.log_port_speed[port]); 2114 } 2115 /* Speed remap for resource */ 2116 for (i = 0; i < port_schedule_state->nport; i++) { 2117 if (-1 != port_schedule_state->resource[i].physical_port) { /* that is, port up */ 2118 port_schedule_state->resource[i].speed = 2119 soc_trident3_port_speed_higig2eth( 2120 port_schedule_state->resource[i].speed); 2121 } 2122 } 2123 } 2124 } 2125 2126 /*! @fn int soc_td3_tdm_get_log_port_speed(int unit, 2127 * soc_port_schedule_state_t *port_schedule_state, 2128 * int log_port, 2129 * int prev_or_new, 2130 * int *speed, 2131 * int *num_lanes) 2132 * @param unit Chip unit number. 2133 * @param port_schedule_state Pointer to a soc_port_schedule_state_t struct 2134 * variable. 2135 * @param log_port: logical port 2136 * @param prev_or_new: if = 1 use in_port_map, otherwise use out_port_map. 2137 * int *speed: port speed returned 2138 * int *num_lanes: num lanes returned 2139 * @brief helper func to get the scheduler speed and num lanes 2140 */ 2141 int 2142 soc_td3_tdm_get_log_port_speed( 2143 int unit, 2144 soc_port_schedule_state_t *port_schedule_state, 2145 int log_port, 2146 int prev_or_new, 2147 int *speed, 2148 int *num_lanes) 2149 { 2150 soc_port_map_type_t *port_map; 2151 2152 if (prev_or_new == 1) { 2153 port_map = &port_schedule_state->in_port_map; 2154 } else { 2155 port_map = &port_schedule_state->out_port_map; 2156 } 2157 2158 *speed = port_map->log_port_speed[log_port]; 2159 *num_lanes = port_map->port_num_lanes[log_port]; 2160 2161 /* If 25G should act as 50G in the scheduler, change speed and num_lanes */ 2162 if (SOC_PBMP_MEMBER(port_map->physical_pbm, log_port) && 2163 (*speed == 25000) ) { 2164 *speed = 50000; 2165 *num_lanes = 2; 2166 } 2167 2168 return SOC_E_NONE; 2169 } 2170 2171 /*** END SDK API COMMON CODE ***/ 2172 2173 #endif /* BCM_TRIDENT3_SUPPORT */