greyhound2_tdm.c (17718B)
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: greyhound2_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_GREYHOUND2_SUPPORT) 20 #include <soc/greyhound2.h> 21 #include <soc/greyhound2_tdm.h> 22 #include <soc/tdm/greyhound2/tdm_gh2_defines.h> 23 24 25 /*** START SDK API COMMON CODE ***/ 26 27 /*! @fn void _soc_gh2_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_gh2_tdm_print_port_map(int unit, soc_port_map_type_t *port_map) 36 { 37 int port; 38 int is_hg2; 39 int speed, phy_port, idb_port, mmu_port, num_lanes; 40 int phy_bmap, p2l_map, m2p_map; 41 42 for (port = 0; port < GREYHOUND2_TDM_LOG_PORTS_PER_DEV; port++) { 43 if (port_map->log_port_speed[port] > 0) { 44 speed = port_map->log_port_speed[port] / 1000; 45 phy_port = port_map->port_l2p_mapping[port]; 46 idb_port = port_map->port_l2i_mapping[port]; 47 mmu_port = port_map->port_p2m_mapping[phy_port]; 48 num_lanes = port_map->port_num_lanes[port]; 49 phy_bmap = SOC_PBMP_MEMBER(port_map->physical_pbm, 50 phy_port) ? 1 : 0; 51 is_hg2 = SOC_PBMP_MEMBER(port_map->hg2_pbm, port) ? 1 : 0; 52 p2l_map = port_map->port_p2l_mapping[phy_port]; 53 m2p_map = port_map->port_m2p_mapping[mmu_port]; 54 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 55 "log_port=%3d phy_port=%3d speed=%3dG " 56 "%s idb_port=%3d mmu_port=%3d " 57 "num_lanes=%1d phy_bmap=%1d " 58 "p2l_map=%3d "), 59 port, phy_port, speed, 60 (is_hg2 == 1) ? "HG2" : "ETH", 61 idb_port, mmu_port, num_lanes, 62 phy_bmap, p2l_map)); 63 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 64 "m2p_map=%3d\n"), 65 m2p_map)); 66 } 67 } 68 } 69 70 /*! @fn void _soc_gh2_tdm_print_tdm_info( 71 int unit, 72 soc_tdm_schedule_t *tdm_info) 73 @param unit Chip unit number. 74 @param tdm_info Pointer to a soc_tdm_schedule_t struct variable. 75 @brief Debug API to print soc_tdm_schedule_t 76 */ 77 void 78 _soc_gh2_tdm_print_tdm_info(int unit, soc_tdm_schedule_t *tdm_info) 79 { 80 int cal_len, j; 81 82 for (cal_len = tdm_info->cal_len; cal_len > 0; cal_len--) { 83 if (tdm_info->linerate_schedule[cal_len - 1] != GH2_NUM_EXT_PORTS) { 84 break; 85 } 86 } 87 88 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 89 "\tMAIN CALENDAR: cal_len=%3d \n"), 90 cal_len )); 91 for (j = 0; j < cal_len; j++) { 92 if (j % 16 == 0) { 93 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 94 "\n%3d :%3d\t"), 95 j, j + 15)); 96 } 97 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 98 "%4d"), 99 tdm_info->linerate_schedule[j])); 100 } 101 102 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "\n"))); 103 } 104 105 106 /*! @fn void _soc_gh2_tdm_print_schedule_state( 107 int unit, 108 soc_port_schedule_state_t *sch_info) 109 @param unit Chip unit number. 110 @param sch_info Pointer to a soc_port_schedule_state_t struct variable. 111 @brief Debug API to print sch_info 112 */ 113 void 114 _soc_gh2_tdm_print_schedule_state(int unit, 115 soc_port_schedule_state_t *sch_info) 116 { 117 int print_tdm; 118 soc_tdm_schedule_t *tdm_schedule; 119 120 print_tdm = 1; 121 122 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 123 "\n\nPRINTING soc_port_schedule_state_t \n"))); 124 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 125 "nport= %3d\n"), 126 sch_info->nport)); 127 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 128 "frequency= %4dMHz\n"), 129 sch_info->frequency)); 130 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 131 "bandwidth= %4d\n"), 132 sch_info->bandwidth)); 133 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 134 "io_bandwidth= %4d\n"), 135 sch_info->io_bandwidth)); 136 137 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 138 "\nPRINTING soc_port_schedule_state_t" 139 "::[in_port_map]\n"))); 140 _soc_gh2_tdm_print_port_map(unit, &sch_info->in_port_map); 141 142 143 if (print_tdm == 1) { 144 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 145 "\n====== TDM Tables \n"))); 146 tdm_schedule = &(sch_info->tdm_ingress_schedule_pipe[0]. \ 147 tdm_schedule_slice[0]); 148 _soc_gh2_tdm_print_tdm_info(unit, tdm_schedule); 149 } 150 } 151 152 /*! @fn int _soc_gh2_tdm_calculation( 153 int unit, 154 soc_port_schedule_state_t *sch_info) 155 @param unit Chip unit number. 156 @param sch_info Pointer to a soc_port_schedule_state_t struct variable. 157 @brief API to calculate TDM tables. 158 */ 159 int 160 _soc_gh2_tdm_calculation(int unit, soc_port_schedule_state_t *sch_info) 161 { 162 int i, phy_port, lgc_port; 163 int pipe = 0; 164 int index; 165 int mgmt_pm_hg = 0; 166 int tdm_idb_cal_len; 167 int *tdm_idb_pipe_main; 168 tdm_soc_t _chip_pkg; 169 tdm_mod_t *_tdm_pkg; 170 uint32 port_speeds[GREYHOUND2_TDM_PHY_PORTS_PER_DEV]; 171 uint32 port_states[GREYHOUND2_TDM_PHY_PORTS_PER_DEV]; 172 int tdm_realloc = 0; 173 174 sal_memset(port_speeds, 0, 175 GREYHOUND2_TDM_PHY_PORTS_PER_DEV * sizeof(uint32)); 176 sal_memset(port_states, 0, 177 GREYHOUND2_TDM_PHY_PORTS_PER_DEV * sizeof(uint32)); 178 179 /* Remap input speeds to ETH bitrates */ 180 soc_gh2_port_schedule_speed_remap(unit, sch_info); 181 182 /* Check if TDM reallocation required. */ 183 tdm_realloc = soc_greyhound2_auto_tdm_realloc(unit); 184 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 185 "TDM reallocation %s.\n"), 186 tdm_realloc ? "on" : "off")); 187 188 /* Set port states and speeds */ 189 for (lgc_port = 0; 190 lgc_port < GREYHOUND2_TDM_PHY_PORTS_PER_DEV; lgc_port++) { 191 if (sch_info->in_port_map.log_port_speed[lgc_port] > 0 ) { 192 phy_port = sch_info->in_port_map.port_l2p_mapping[lgc_port]; 193 194 if (tdm_realloc) { 195 if ((sch_info->in_port_map.log_port_speed[lgc_port] == 1000) && 196 (lgc_port != 0)) { 197 sch_info->in_port_map.log_port_speed[lgc_port] = 2500; 198 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 199 "TDM reallocation. " 200 "Override lport(%d) speed to 2.5G\n"), 201 lgc_port)); 202 } 203 } 204 205 if (phy_port < GREYHOUND2_TDM_PHY_PORTS_PER_DEV) { 206 if (SOC_PBMP_MEMBER(sch_info->in_port_map.hg2_pbm, lgc_port)) { 207 port_states[phy_port] = PORT_STATE__LINERATE_HG; 208 } else { 209 port_states[phy_port] = PORT_STATE__LINERATE; 210 } 211 port_speeds[phy_port] = sch_info->in_port_map. \ 212 log_port_speed[lgc_port]; 213 } 214 } 215 } 216 /* Print input config */ 217 if (LOG_CHECK(BSL_LS_SOC_TDM | BSL_INFO)) { 218 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 219 "frequency: %dMHz\n"), 220 sch_info->frequency)); 221 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 222 "%8s%8s%8s\n"), 223 "port", "speed", "state")); 224 for (phy_port = 0; 225 phy_port < GREYHOUND2_TDM_PHY_PORTS_PER_DEV; phy_port++) { 226 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 227 "%8d%8d%8d\n"), 228 phy_port, port_speeds[phy_port] / 1000, 229 port_states[phy_port])); 230 } 231 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "\n"))); 232 } 233 /* Initialize input variables for SW TDM Generation: 234 -- unit 235 -- num_ext_ports 236 -- state 237 -- speed 238 -- clk_freq 239 */ 240 _chip_pkg.unit = unit; 241 _chip_pkg.num_ext_ports = GH2_NUM_EXT_PORTS; 242 _chip_pkg.state = sal_alloc((_chip_pkg.num_ext_ports)*sizeof(int), 243 "port state list"); 244 if (_chip_pkg.state == NULL) { 245 return SOC_E_MEMORY; 246 } 247 _chip_pkg.speed = sal_alloc((_chip_pkg.num_ext_ports)*sizeof(int), 248 "port speed list"); 249 if (_chip_pkg.speed == NULL) { 250 sal_free(_chip_pkg.state); 251 return SOC_E_MEMORY; 252 } 253 for (index = 0; index < _chip_pkg.num_ext_ports; index++) { 254 _chip_pkg.state[index] = 0; 255 _chip_pkg.speed[index] = 0; 256 } 257 for (index = 0; 258 index < _chip_pkg.num_ext_ports && 259 index < GREYHOUND2_TDM_PHY_PORTS_PER_DEV; index++) { 260 _chip_pkg.state[index] = port_states[index]; 261 _chip_pkg.speed[index] = port_speeds[index]; 262 } 263 /* Shift port state to left one position; required by C_TDM */ 264 for (index = 1; index < _chip_pkg.num_ext_ports; index++) { 265 _chip_pkg.state[index - 1] = _chip_pkg.state[index]; 266 } 267 _chip_pkg.clk_freq = sch_info->frequency; 268 _chip_pkg.soc_vars.gh2.mgmt_pm_hg = mgmt_pm_hg; 269 _chip_pkg.soc_vars.gh2.tdm_chk_en = 1; 270 271 /* Populate TDM tables by invoking SW TDM API */ 272 /* coverity[uninit_use_in_call : FALSE] */ 273 _tdm_pkg = _soc_set_tdm_tbl(SOC_SEL_TDM(&_chip_pkg)); 274 275 /* Free the memory allocated to port states and speeds */ 276 sal_free(_chip_pkg.state); 277 sal_free(_chip_pkg.speed); 278 279 /* Copy TDM result into output structure */ 280 if (_tdm_pkg == NULL) { 281 LOG_CLI((BSL_META_U(unit, 282 "Unsupported config for TDM calendar " 283 "generation\n"))); 284 return SOC_E_FAIL; 285 } else { 286 /* IDB calendar (0) */ 287 tdm_idb_pipe_main = _tdm_pkg->_chip_data.cal_0.cal_main; 288 tdm_idb_cal_len = _tdm_pkg->_chip_data.cal_0.cal_len; 289 290 if (tdm_idb_pipe_main == NULL) { 291 LOG_CLI((BSL_META_U(unit, 292 "Unsupported config for TDM calendar " 293 "generation\n"))); 294 tdm_gh2_free(_tdm_pkg); 295 sal_free(_tdm_pkg); 296 return SOC_E_FAIL; 297 } else { 298 /* IDB TDM main calendar */ 299 for (index = 0; index < tdm_idb_cal_len; index++) { 300 sch_info->tdm_ingress_schedule_pipe[pipe]. \ 301 tdm_schedule_slice[0].linerate_schedule[index] = \ 302 tdm_idb_pipe_main[index]; 303 } 304 sch_info->tdm_ingress_schedule_pipe[pipe].tdm_schedule_slice[0]. \ 305 cal_len = tdm_idb_cal_len; 306 } 307 308 /* Free the memory allocated in TDM algorithm code */ 309 tdm_gh2_free(_tdm_pkg); 310 sal_free(_tdm_pkg); 311 } 312 313 /* Print TDM result */ 314 pipe = 0; 315 /* IDB TDM main calendar */ 316 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 317 "Pipe %d [IDB TDM main calendar]\n"), 318 pipe)); 319 for (index = 0; index < MAX_CAL_LEN; index++) { 320 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 321 " %3d"), 322 sch_info->tdm_ingress_schedule_pipe[pipe]. \ 323 tdm_schedule_slice[0].linerate_schedule[index])); 324 if (((index + 1) % 16 == 0) && index > 0) { 325 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "\n"))); 326 } 327 } 328 LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "\n"))); 329 330 /* If init then just copy in_port_map to out_port_map*/ 331 if (sch_info->is_flexport == 0) { 332 for (i = 0; i < SOC_MAX_NUM_PORTS; i++) { 333 sch_info->out_port_map.log_port_speed[i] = 334 sch_info->in_port_map.log_port_speed[i]; 335 sch_info->out_port_map.port_p2l_mapping[i] = 336 sch_info->in_port_map.port_p2l_mapping[i]; 337 sch_info->out_port_map.port_l2p_mapping[i] = 338 sch_info->in_port_map.port_l2p_mapping[i]; 339 sch_info->out_port_map.port_p2m_mapping[i] = 340 sch_info->in_port_map.port_p2m_mapping[i]; 341 sch_info->out_port_map.port_num_lanes[i] = 342 sch_info->in_port_map.port_num_lanes[i]; 343 } 344 for (i = 0; i < SOC_MAX_NUM_MMU_PORTS; i++) { 345 sch_info->out_port_map.port_m2p_mapping[i] = 346 sch_info->in_port_map.port_m2p_mapping[i]; 347 } 348 for (i = 0; i < _SHR_PBMP_WORD_MAX; i++) { 349 sch_info->out_port_map.physical_pbm.pbits[i] = 350 sch_info->in_port_map.physical_pbm.pbits[i]; 351 sch_info->out_port_map.hg2_pbm.pbits[i] = 352 sch_info->in_port_map.hg2_pbm.pbits[i]; 353 } 354 } 355 356 _soc_gh2_tdm_print_schedule_state(unit, sch_info); 357 358 return SOC_E_NONE; 359 } 360 361 362 /*! @fn int _soc_gh2_tdm_set_idb_calendar( 363 int unit, 364 soc_port_schedule_state_t *sch_info) 365 @param unit Chip unit number. 366 @param sch_info Pointer to a soc_port_schedule_state_t struct variable. 367 @brief API to initialize the TD3 IDB main calendar. 368 */ 369 int 370 _soc_gh2_tdm_set_idb_calendar(int unit, soc_port_schedule_state_t *sch_info) 371 { 372 int rv = SOC_E_NONE; 373 uint32 cal_len; 374 int pipe, slot, length; 375 uint32 rval; 376 iarb_tdm_table_entry_t iarb_tdm; 377 mmu_arb_tdm_table_entry_t mmu_arb_tdm; 378 int mmu_port, phy_port; 379 soc_info_t *si; 380 381 si = &SOC_INFO(unit); 382 383 pipe = 0; 384 /* TDM Calendar is always taken from slice 0 */ 385 cal_len = sch_info->tdm_ingress_schedule_pipe[pipe]. \ 386 tdm_schedule_slice[0].cal_len; 387 for (length = cal_len; length > 0; length--) { 388 if (sch_info->tdm_ingress_schedule_pipe[pipe].tdm_schedule_slice[ 389 0].linerate_schedule[length - 1] != GH2_NUM_EXT_PORTS) { 390 break; 391 } 392 } 393 394 SOC_IF_ERROR_RETURN(READ_IARB_TDM_CONTROLr(unit, &rval)); 395 soc_reg_field_set(unit, IARB_TDM_CONTROLr, &rval, DISABLEf, 1); 396 soc_reg_field_set(unit, IARB_TDM_CONTROLr, &rval, TDM_WRAP_PTRf, 83); 397 SOC_IF_ERROR_RETURN(WRITE_IARB_TDM_CONTROLr(unit, rval)); 398 399 for (slot = 0; slot < length; slot ++) { 400 phy_port = sch_info->tdm_ingress_schedule_pipe[ 401 pipe].tdm_schedule_slice[0].linerate_schedule[slot]; 402 if (phy_port == -1) { 403 /* Convert IDLE slot definition */ 404 phy_port = 127; 405 } 406 mmu_port = (phy_port != 127) ? si->port_p2m_mapping[phy_port] : 127; 407 408 sal_memset(&iarb_tdm, 0, sizeof(iarb_tdm_table_entry_t)); 409 sal_memset(&mmu_arb_tdm, 0, sizeof(mmu_arb_tdm_table_entry_t)); 410 411 soc_IARB_TDM_TABLEm_field32_set(unit, &iarb_tdm, PORT_NUMf, 412 phy_port); 413 soc_MMU_ARB_TDM_TABLEm_field32_set(unit, &mmu_arb_tdm, PORT_NUMf, 414 mmu_port); 415 416 if (slot == length - 1) { 417 soc_MMU_ARB_TDM_TABLEm_field32_set(unit, &mmu_arb_tdm, WRAP_ENf, 1); 418 } 419 SOC_IF_ERROR_RETURN(WRITE_IARB_TDM_TABLEm(unit, SOC_BLOCK_ALL, slot, 420 &iarb_tdm)); 421 SOC_IF_ERROR_RETURN(WRITE_MMU_ARB_TDM_TABLEm(unit, SOC_BLOCK_ALL, slot, 422 &mmu_arb_tdm)); 423 424 } 425 rval = 0; 426 soc_reg_field_set(unit, IARB_TDM_CONTROLr, &rval, DISABLEf, 0); 427 soc_reg_field_set(unit, IARB_TDM_CONTROLr, &rval, TDM_WRAP_PTRf, 428 length -1); 429 SOC_IF_ERROR_RETURN(WRITE_IARB_TDM_CONTROLr(unit, rval)); 430 431 /* Update TDM size info */ 432 rv = soc_gh2_tdm_size_set(unit, length); 433 434 return rv; 435 } 436 437 /*! @fn int soc_gh2_tdm_init( 438 int unit, 439 soc_port_schedule_state_t *sch_info) 440 @param unit Chip unit number. 441 @param sch_info Pointer to a soc_port_schedule_state_t struct variable. 442 @brief Main API for TDM init 443 */ 444 int soc_gh2_tdm_init(int unit, soc_port_schedule_state_t *sch_info) 445 { 446 SOC_IF_ERROR_RETURN(_soc_gh2_tdm_calculation(unit, sch_info)); 447 448 SOC_IF_ERROR_RETURN(_soc_gh2_tdm_set_idb_calendar(unit, sch_info)); 449 450 return SOC_E_NONE; 451 } 452 453 /*! @fn int soc_gh2_port_speed_higig2eth(int speed) 454 * @param int speed 455 * @brief Map port speed to ETH bitrates 456 */ 457 static int 458 soc_gh2_port_speed_higig2eth(int speed) 459 { 460 switch (speed) { 461 case 11000: 462 /* 10G */ 463 return 10000; 464 case 21000: 465 /* 20G */ 466 return 20000; 467 case 42000: 468 /* 40G */ 469 return 40000; 470 case 53000: 471 /* 50G */ 472 return 50000; 473 default: 474 return speed; 475 } 476 } 477 478 /*! @fn void soc_gh2_port_schedule_speed_remap(int unit, 479 * soc_port_schedule_state_t *port_schedule_state) 480 * @param unit Chip unit number. 481 * @param port_schedule_state Pointer to a soc_port_schedule_state_t struct 482 * variable. 483 * @brief API to remap speeds to ETH bitrates 484 */ 485 void 486 soc_gh2_port_schedule_speed_remap( 487 int unit, 488 soc_port_schedule_state_t *port_schedule_state) 489 { 490 int port; 491 492 /* Speed remap for in_port_map*/ 493 for (port = 0; port < SOC_MAX_NUM_PORTS; port++) { 494 port_schedule_state->in_port_map.log_port_speed[port] = 495 soc_gh2_port_speed_higig2eth( 496 port_schedule_state->in_port_map.log_port_speed[port]); 497 } 498 499 } 500 501 /*** END SDK API COMMON CODE ***/ 502 503 #endif /* BCM_GREYHOUND2_SUPPORT */