portctrl.c (173783B)
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: portctrl.c 8 * Purpose: SDK Port Control Layer 9 * 10 * The purpose is to encapsulate port functionality 11 * related to the xxPORT block (i.e. XLPORT, CPORT) 12 * MAC and PHY. 13 * 14 * Currently, only the PortMod library is being supported. 15 * The PortMod library provides support for the MAC, PHY, 16 * and xxPORT registers. 17 */ 18 19 #include <shared/bsl.h> 20 #include <soc/error.h> 21 #include <soc/esw/portctrl.h> 22 #include <soc/esw/portctrl_internal.h> 23 #include <soc/esw/port.h> 24 #include <bcm_int/esw/port.h> 25 26 #ifdef PORTMOD_SUPPORT 27 #include <soc/phy/phymod_sim.h> 28 #include <soc/portmod/portmod.h> 29 #include <soc/portmod/portmod_common.h> 30 #include <soc/phy/phymod_port_control.h> 31 #include <soc/portmod/portmod_chain.h> 32 #include <soc/portmod/portmod_legacy_phy.h> 33 34 /* Indicates if the Port Control module has been initalized */ 35 static int portctrl_init[SOC_MAX_NUM_DEVICES]; 36 37 /* 38 * Define: 39 * PORTCTRL_PORT_TO_PPORT 40 * Purpose: 41 * Converts a SOC port into port type used in PortMod functions '_pport' 42 */ 43 #define PORTCTRL_PORT_TO_PPORT(_port, _pport) do { \ 44 _pport = _port; \ 45 } while (0) 46 47 static phymod_bus_t portmod_ext_default_bus = { 48 "MDIO Bus", 49 portmod_ext_phy_mdio_c45_reg_read, 50 portmod_ext_phy_mdio_c45_reg_write, 51 NULL, 52 portmod_common_mutex_take, 53 portmod_common_mutex_give, 54 NULL, 55 NULL, 56 PHYMOD_BUS_CAP_WR_MODIFY | PHYMOD_BUS_CAP_LANE_CTRL 57 }; 58 59 extern uint32_t phymod_dbg_mask; 60 extern uint32_t phymod_dbg_addr; 61 extern uint32_t phymod_dbg_lane; 62 63 /* Used by timestamp adjust */ 64 typedef struct { 65 int speed; 66 char *props[2]; 67 } portctrl_ts_adjust_cfg_t; 68 69 static portctrl_ts_adjust_cfg_t ts_adjust_props[] = { 70 {10, {spn_TIMESTAMP_ADJUST_10MBE_NS, spn_TIMESTAMP_TSTS_ADJUST_10MBE_NS}}, 71 {100, {spn_TIMESTAMP_ADJUST_100MBE_NS, spn_TIMESTAMP_TSTS_ADJUST_100MBE_NS}}, 72 {1000, {spn_TIMESTAMP_ADJUST_1GBE_NS, spn_TIMESTAMP_TSTS_ADJUST_1GBE_NS}}, 73 {2500, {spn_TIMESTAMP_ADJUST_2_5GBE_NS, spn_TIMESTAMP_TSTS_ADJUST_2_5GBE_NS}}, 74 {10000, {spn_TIMESTAMP_ADJUST_10GBE_NS, spn_TIMESTAMP_TSTS_ADJUST_10GBE_NS}}, 75 {25000, {spn_TIMESTAMP_ADJUST_25GBE_NS, spn_TIMESTAMP_TSTS_ADJUST_25GBE_NS}}, 76 {40000, {spn_TIMESTAMP_ADJUST_40GBE_NS, spn_TIMESTAMP_TSTS_ADJUST_40GBE_NS}}, 77 {50000, {spn_TIMESTAMP_ADJUST_50GBE_NS, spn_TIMESTAMP_TSTS_ADJUST_50GBE_NS}}, 78 {100000, {spn_TIMESTAMP_ADJUST_100GBE_NS, spn_TIMESTAMP_TSTS_ADJUST_100GBE_NS}}, 79 {-1, {spn_TIMESTAMP_ADJUST_NS, spn_TIMESTAMP_TSTS_ADJUST_NS}} 80 }; 81 82 /* 83 * Function: 84 * soc_esw_portctrl_init_check 85 * Purpose: 86 * check if portctrl is already initialized. 87 * Parameters: 88 * unit - (IN) Unit number. 89 * Returns: 90 * SOC_E_NONE : Initialized 91 * SOC_E_INIT : Not Initialized. 92 */ 93 int 94 soc_esw_portctrl_init_check(int unit) 95 { 96 if (SOC_PORTCTRL_NOT_INITIALIZED == portctrl_init[unit]) { 97 return SOC_E_INIT; 98 } 99 return SOC_E_NONE; 100 } 101 102 /* 103 * Function: 104 * soc_esw_portctrl_pm_user_access_alloc 105 * Purpose: 106 * Allocate SW data structure for the port macros (PM). 107 * Parameters: 108 * unit - (IN) Unit number. 109 * num - (IN) Number of PM port macros in device. 110 * user_acc - (OUT) Returns allocated PMs structures. 111 * Returns: 112 * SOC_E_XXX 113 */ 114 int 115 soc_esw_portctrl_pm_user_access_alloc(int unit, int num, 116 portmod_default_user_access_t **user_acc) 117 { 118 if (*user_acc == NULL) { 119 *user_acc = sal_alloc(sizeof(portmod_default_user_access_t) * num, 120 "PortMod PM"); 121 if (*user_acc == NULL) { 122 return SOC_E_MEMORY; 123 } 124 } 125 sal_memset(*user_acc, 0, sizeof(portmod_default_user_access_t) * num); 126 127 return SOC_E_NONE; 128 } 129 130 /* 131 * Function: 132 * soc_esw_portctrl_dump_txrx_lane_map 133 * Purpose: 134 * Utility function to dump tx, rx lane map 135 * Parameters: 136 * unit - (IN) Unit number. 137 * Returns: 138 * SOC_E_XXX 139 */ 140 void 141 soc_esw_portctrl_dump_txrx_lane_map(int unit, int first_port, int logical_port, 142 int core_num, uint32 txlane_map_b, uint32 rxlane_map_b, 143 uint32 txlane_map, uint32 rxlane_map) 144 { 145 static int hdr_flag =0; 146 if (!hdr_flag) { 147 LOG_ERROR(BSL_LS_SOC_PORT, 148 (BSL_META_UP(unit, logical_port, 149 "+-------+-------+-------+-------+------+--------+--------+\n"))); 150 LOG_ERROR(BSL_LS_SOC_PORT, 151 (BSL_META_UP(unit, logical_port, 152 "| PPORT | LPORT | TXMAP | RXMAP | CORE | TXSWAP | RXSWAP |\n"))); 153 LOG_ERROR(BSL_LS_SOC_PORT, 154 (BSL_META_UP(unit, logical_port, 155 "+-------+-------+-------+-------+------+--------+--------+\n"))); 156 hdr_flag=1; 157 } 158 LOG_ERROR(BSL_LS_SOC_PORT, 159 (BSL_META_UP(unit, logical_port, 160 "| %04d | %04d | %04X | %04X | %02d | %04X | %04X |\n"), 161 first_port, logical_port, txlane_map_b, rxlane_map_b, core_num, 162 txlane_map, rxlane_map)); 163 164 LOG_ERROR(BSL_LS_SOC_PORT, 165 (BSL_META_UP(unit, logical_port, 166 "+-------+-------+-------+-------+------+--------+--------+\n"))); 167 return; 168 } 169 170 /* 171 * Function: 172 * soc_esw_portctrl_ext_phy_config_parameter_get 173 * Purpose: 174 * To extract external phy parameter from config.bcm. 175 * Parameters: 176 * unit - (IN) Unit number. 177 * port - (IN) Logical Port Number 178 * phy_addr - (OUT) Ext Phy MDIO address. 0xFF mean no ext phy 179 * shift - (IN) Phy Port Map Shift from internal map. ( default 0) 180 * Returns: 181 * BCM_E_XXX 182 */ 183 STATIC int 184 soc_esw_portctrl_ext_phy_config_parameter_get (int unit, int port, 185 uint32 *phy_addr, uint32 *num_int_cores, uint32 shift[3]) 186 { 187 char *config_str, *sub_str, *sub_str_end; 188 int idx; 189 190 /* set default return values. */ 191 *num_int_cores = 1; 192 shift[0] = 0; 193 shift[1] = 0; 194 shift[2] = 0; 195 196 config_str = soc_property_port_get_str(unit, port, spn_PORT_PHY_ADDR); 197 if (config_str == NULL) { 198 *phy_addr = 0xFF; /* NO PHY */ 199 return SOC_E_NONE; 200 } 201 202 /* 203 * port_phy_addr_<port>=<phy addr>:<num_int_cores>:<shift0>:<shift1>:<shift2> 204 */ 205 sub_str = config_str; 206 207 /* Parse phy address number */ 208 *phy_addr = sal_ctoi(sub_str, &sub_str_end); 209 210 if (*sub_str_end == '\0') 211 { 212 return SOC_E_NONE ; 213 } 214 215 /* Skip ':' between physical port number and num_internal_cores */ 216 sub_str = sub_str_end; 217 if (*sub_str != '\0') { 218 if (*sub_str != ':') { 219 LOG_CLI((BSL_META_U(unit, "Port %d: Bad config string \"%s\"\n"), 220 port, config_str)); 221 return SOC_E_FAIL; 222 } 223 sub_str++; 224 } else { 225 return SOC_E_NONE; 226 } 227 228 /* parse num of cores. */ 229 *num_int_cores = sal_ctoi(sub_str, &sub_str_end); 230 if (*num_int_cores > SOC_PM12X10_PM4X10_COUNT) { 231 LOG_CLI((BSL_META_U(unit, 232 "Port %d: Bad config string bad num of cores \"%s\" %d \n"), 233 port, config_str, *num_int_cores)); 234 return SOC_E_FAIL; 235 236 } 237 238 /* check for end of string. */ 239 if( *sub_str_end == '\0' ) 240 { 241 return SOC_E_NONE ; 242 } 243 244 for (idx=0; idx < *num_int_cores; idx++) { 245 /* Skip ':' between physical port number and num_internal_cores */ 246 sub_str = sub_str_end; 247 if (*sub_str != '\0') { 248 if (*sub_str != ':') { 249 LOG_CLI((BSL_META_U(unit, "Port %d: Bad config string \"%s\"\n"), 250 port, config_str)); 251 return SOC_E_FAIL; 252 } 253 sub_str++; 254 } 255 shift[idx] = sal_ctoi(sub_str, &sub_str_end); 256 /* check for end of string. */ 257 if( *sub_str_end == '\0' ) 258 { 259 return SOC_E_NONE ; 260 } 261 } 262 return SOC_E_NONE; 263 } 264 265 typedef struct soc_esw_portctrl_phy_toplogy_s { 266 uint16_t pport; /* Physical port number */ 267 uint16_t xphy_index; /* position of the external phy in the phy chain */ 268 uint16_t xphy_id; /* Mdio address of the external phy */ 269 int16_t sys_lane; /* system side lane number connected to the internal pport */ 270 int16_t line_lane; /* corresponding line side lane number */ 271 uint16_t is_default; 272 } soc_esw_portctrl_phy_toplogy_t; 273 274 /* 275 * Function: 276 * soc_esw_portctrl_ext_phy_config_topology_get 277 * Purpose: 278 * To extract external phy topology from config.bcm. 279 * Parameters: 280 * unit - (IN) Unit number. 281 * topology - (OUT) topology information of the physical port 282 * Returns: 283 * BCM_E_XXX 284 */ 285 STATIC int 286 soc_esw_portctrl_ext_phy_config_topology_get (int unit, soc_esw_portctrl_phy_toplogy_t *topology) 287 { 288 289 char *config_str, *sub_str, *sub_str_end; 290 char pport[8]; 291 292 topology->is_default = 0; 293 sal_itoa(pport, topology->pport, 10, 0, 0); 294 295 config_str = soc_property_suffix_num_str_get(unit, topology->xphy_index, spn_PHY_TOPOLOGY, 296 sal_strcat(pport, "_")); 297 298 if (config_str == NULL) { 299 /* No config found. There is a logical to logical port 300 mapping present in the system */ 301 topology->xphy_id = 0xFF; 302 topology->sys_lane = -1; 303 topology->line_lane = -1; 304 topology->is_default = 1; 305 return SOC_E_NONE; 306 } 307 308 /* 309 * phy_topology_<pport_xphy_index>=<xphy_id>:<sys_lane>:<line_lane> 310 */ 311 sub_str = config_str; 312 313 /* Parse phy address number */ 314 topology->xphy_id = sal_ctoi(sub_str, &sub_str_end); 315 316 /* Skip ':' between phy address and sys lane */ 317 sub_str = sub_str_end; 318 if (*sub_str != '\0') { 319 if (*sub_str != ':') { 320 LOG_CLI((BSL_META_U(unit, "Physical Port %d: Bad config string \"%s\"\n"), 321 topology->pport, config_str)); 322 return SOC_E_FAIL ; 323 } 324 sub_str++; 325 } else { 326 LOG_CLI((BSL_META_U(unit, "Physical Port %d: Bad config string \"%s\"\n"), 327 topology->pport, config_str)); 328 return SOC_E_FAIL ; 329 } 330 331 /* parse sys lane */ 332 topology->sys_lane = sal_ctoi(sub_str, &sub_str_end); 333 sub_str = sub_str_end; 334 335 if (*sub_str != '\0') { 336 if (*sub_str != ':') { 337 LOG_CLI((BSL_META_U(unit, "Physical Port %d: Bad config string \"%s\"\n"), 338 topology->pport, config_str)); 339 return SOC_E_FAIL ; 340 } 341 sub_str++; 342 } else { 343 LOG_CLI((BSL_META_U(unit, "Physical Port %d: Bad config string \"%s\"\n"), 344 topology->pport, config_str)); 345 return SOC_E_FAIL; 346 } 347 348 /* parse line lane */ 349 topology->line_lane = sal_ctoi(sub_str, &sub_str_end); 350 sub_str = sub_str_end; 351 352 /* look for end of config string */ 353 if (*sub_str != '\0') { 354 LOG_CLI((BSL_META_U(unit, "Physical Port %d: Bad config string \"%s\"\n"), 355 topology->pport, config_str)); 356 return SOC_E_FAIL; 357 } 358 359 return SOC_E_NONE; 360 } 361 362 int 363 soc_esw_portctrl_xphy_default_core_access_get(int unit, phymod_core_access_t *core_access) 364 { 365 int rv = SOC_E_NONE; 366 portmod_default_user_access_t* local_user_access; 367 368 PORTMOD_IF_ERROR_RETURN(phymod_core_access_t_init(core_access)); 369 core_access->access.bus = &portmod_ext_default_bus; 370 core_access->type = phymodDispatchTypeInvalid; /* Make sure it is invalid. */ 371 local_user_access = sal_alloc(sizeof(portmod_default_user_access_t), 372 "xphy_user_acc"); 373 if(local_user_access == NULL){ 374 LOG_CLI((BSL_META_U(unit, "soc_esw_portctrl_xphy_default_core_access_get local_user_access is NULL.\n"))); 375 return SOC_E_FAIL; 376 } 377 sal_memset(local_user_access, 0, sizeof(portmod_default_user_access_t)); 378 local_user_access->unit = unit; 379 core_access->access.user_acc = local_user_access; 380 return rv; 381 382 } 383 384 static int 385 soc_esw_portctrl_core_config_update(int unit, int lport, int pport, int lane, uint32_t xphy_addr, int phy_idx) { 386 387 int rv = SOC_E_NONE; 388 int fw_ld_method = 0x1, i; 389 uint32_t rx_polarity, tx_polarity; 390 uint32_t rx_lane_map, tx_lane_map; 391 uint32_t psc_repeater_mode = 0; 392 uint32_t port_phy_clause = 45; 393 394 uint8_t gearbox_enable; 395 uint8_t pin_compatibility_enable; 396 uint8_t phy_mode_reverse; 397 int force_fw_load, is_legacy_phy; 398 phymod_firmware_load_method_t fw_load_method; 399 phymod_core_access_t core_access; 400 phymod_polarity_t polarity; 401 phymod_lane_map_t lane_map; 402 403 rx_polarity = 0; 404 tx_polarity = 0; 405 rx_lane_map = 0; 406 tx_lane_map = 0; 407 408 /* soc read for phy device operation mode */ 409 gearbox_enable = (soc_property_port_get(unit, lport, spn_PHY_GEARBOX_ENABLE, FALSE)); 410 pin_compatibility_enable = soc_property_port_get(unit, lport, 411 spn_PHY_PIN_COMPATIBILITY_ENABLE, FALSE); 412 psc_repeater_mode = soc_property_port_get(unit, lport, spn_PHY_PCS_REPEATER, 0); 413 phy_mode_reverse = soc_property_port_get(unit, lport, spn_PORT_PHY_MODE_REVERSE, 0); 414 port_phy_clause = soc_property_port_get(unit, lport, spn_PORT_PHY_CLAUSE, 45); 415 416 PORTMOD_IF_ERROR_RETURN(portmod_xphy_core_access_get(unit, xphy_addr, &core_access, &is_legacy_phy)); 417 core_access.device_op_mode = 0; 418 419 if(gearbox_enable) { 420 PHYMOD_INTF_CONFIG_PHY_GEARBOX_ENABLE_SET(&core_access); 421 } 422 423 if (pin_compatibility_enable) { 424 PHYMOD_INTF_CONFIG_PHY_PIN_COMPATIBILITY_ENABLE_SET(&core_access); 425 } 426 427 if (phy_mode_reverse) { 428 PHYMOD_INTF_CONFIG_PORT_PHY_MODE_REVERSE_SET(&core_access); 429 } 430 431 if (psc_repeater_mode) { 432 PHYMOD_INTF_CONFIG_PHY_PSC_REPEATER_MODE_SET(&core_access); 433 } 434 435 if (45 == port_phy_clause) { 436 PHYMOD_ACC_F_CLAUSE45_SET(&core_access.access); 437 } 438 439 /* since core_access got change, save it. device_op_mode is also save to 440 wb buffer inside portmod_xphy_core_access_set. */ 441 442 PORTMOD_IF_ERROR_RETURN(portmod_xphy_core_access_set(unit, xphy_addr, &core_access, is_legacy_phy)); 443 444 /*lower nibble to represent Force FW load and upper nibble to represent 445 load method */ 446 fw_ld_method = 0x11; 447 fw_ld_method = soc_property_port_get(unit, lport, 448 spn_PHY_FORCE_FIRMWARE_LOAD, fw_ld_method); 449 switch ((fw_ld_method >> 4) & 0xf) { 450 case 0: 451 fw_load_method = phymodFirmwareLoadMethodNone; 452 break; 453 case 1: 454 fw_load_method = phymodFirmwareLoadMethodInternal; 455 break; 456 case 2: 457 fw_load_method = phymodFirmwareLoadMethodProgEEPROM; 458 break; 459 default: 460 fw_load_method = phymodFirmwareLoadMethodInternal; 461 break; 462 } 463 464 PORTMOD_IF_ERROR_RETURN(portmod_xphy_fw_load_method_set(unit, xphy_addr, fw_load_method)); 465 switch (fw_ld_method & 0xf) { 466 case 0: 467 /* skip download */ 468 force_fw_load = phymodFirmwareLoadSkip; 469 break; 470 case 1: 471 /* force download */ 472 force_fw_load = phymodFirmwareLoadForce; 473 break; 474 case 2: 475 /* auto download. download firware if two versions are diffirent */ 476 force_fw_load = phymodFirmwareLoadAuto; 477 break; 478 default: 479 force_fw_load = phymodFirmwareLoadSkip; 480 break; 481 } 482 PORTMOD_IF_ERROR_RETURN(portmod_xphy_force_fw_load_set(unit, xphy_addr, force_fw_load)); 483 484 PORTMOD_IF_ERROR_RETURN(portmod_xphy_polarity_get(unit, xphy_addr, &polarity)); 485 /* get the plarity settings for the core. look for the legacy config (logical port based) if 486 * not available then look for a new config mode */ 487 rx_polarity = soc_property_phy_get (unit, pport, phy_idx, 0, 0, 488 spn_PHY_CHAIN_RX_POLARITY_FLIP_PHYSICAL, 0xFFFFFFFF); 489 if (rx_polarity == 0xFFFFFFFF) { 490 rx_polarity = soc_property_port_get(unit, lport, 491 spn_PHY_RX_POLARITY_FLIP, 0); 492 } else { 493 rx_polarity = (rx_polarity & 0x1) << lane; ; 494 } 495 496 tx_polarity = soc_property_phy_get (unit, pport, phy_idx, 0, 0, 497 spn_PHY_CHAIN_TX_POLARITY_FLIP_PHYSICAL, 0xFFFFFFFF); 498 if (tx_polarity == 0xFFFFFFFF) { 499 tx_polarity = soc_property_port_get(unit, lport, 500 spn_PHY_TX_POLARITY_FLIP, 0); 501 } else { 502 tx_polarity = (tx_polarity & 0x1) << lane; ; 503 } 504 505 polarity.rx_polarity |= rx_polarity; 506 polarity.tx_polarity |= tx_polarity; 507 PORTMOD_IF_ERROR_RETURN(portmod_xphy_polarity_set(unit, xphy_addr, polarity)); 508 509 /* get the lane map information */ 510 rx_lane_map = soc_property_phy_get (unit, pport, phy_idx, 0, 0, 511 spn_PHY_CHAIN_RX_LANE_MAP_PHYSICAL, 0xFFFFFFFF); 512 if (rx_lane_map == 0xFFFFFFFF) { 513 rx_lane_map = soc_property_phy_get(unit, pport, phy_idx, 0, 0, 514 spn_PHY_RX_LANE_MAP, 0xFFFFFFFF); 515 } 516 if (rx_lane_map == 0xFFFFFFFF) { 517 rx_lane_map = soc_property_port_get(unit, lport, 518 spn_PHY_RX_LANE_MAP, 0x3210); 519 } 520 521 /* get the lane map information */ 522 tx_lane_map = soc_property_phy_get (unit, pport, phy_idx, 0, 0, 523 spn_PHY_CHAIN_TX_LANE_MAP_PHYSICAL, 0xFFFFFFFF); 524 if (tx_lane_map == 0xFFFFFFFF) { 525 tx_lane_map = soc_property_phy_get(unit, pport, phy_idx, 0, 0, 526 spn_PHY_TX_LANE_MAP, 0xFFFFFFFF); 527 } 528 if (tx_lane_map == 0xFFFFFFFF) { 529 tx_lane_map = soc_property_port_get(unit, lport, 530 spn_PHY_TX_LANE_MAP, 0x3210); 531 } 532 533 /*FIX harcoding the number of lanes to 4 for now 534 * need to figure out the better way to fix this */ 535 lane_map.num_of_lanes = 4; 536 for (i = 0; i < 4; i++) { 537 lane_map.lane_map_rx[i] = ((rx_lane_map >> (i*4)) & 0xf); 538 lane_map.lane_map_tx[i] = ((tx_lane_map >> (i*4)) & 0xf); 539 } 540 541 PORTMOD_IF_ERROR_RETURN(portmod_xphy_lane_map_set(unit, xphy_addr, lane_map)); 542 543 return rv; 544 } 545 546 /* 547 * Function: 548 * soc_esw_portctrl_xphy_wb_db_restore(nt unit, soc_pbmp_t phy_ports) 549 * Purpose: 550 * To restore all external phy data bases on warmboot. 551 * Parameters: 552 * unit - (IN) Unit number. 553 * phy_ports - (IN) lane bit map of the phy. 554 * Returns: 555 * BCM_E_XXX 556 */ 557 int 558 soc_esw_portctrl_xphy_wb_db_restore(int unit) 559 { 560 561 xphy_pbmp_t valid_phys; 562 phymod_core_access_t core_access; 563 int xphy_idx; 564 int xphy_addr; 565 566 PORTMOD_IF_ERROR_RETURN(portmod_xphy_all_valid_phys_get(unit, &valid_phys)); 567 568 /* iterate all the external phy that need to be restored. */ 569 XPHY_PBMP_ITER(valid_phys, xphy_idx){ 570 571 PORTMOD_IF_ERROR_RETURN(portmod_xphy_db_addr_get(unit, xphy_idx, &xphy_addr)); 572 PORTMOD_IF_ERROR_RETURN(soc_esw_portctrl_xphy_default_core_access_get(unit, &core_access)); 573 PORTMOD_IF_ERROR_RETURN(portmod_xphy_wb_db_restore(unit,xphy_idx, xphy_addr,&core_access)); 574 } 575 return SOC_E_NONE; 576 } 577 578 579 /* 580 * Function: 581 * soc_esw_portctrl_setup_ext_phy_add(int unit, int port, portmod_pbmp_t phy_ports) 582 * Purpose: 583 * Add External PHY info. 584 * Parameters: 585 * unit - (IN) Unit number. 586 * phy_ports - (IN) lane bit map of the phy. 587 * Returns: 588 * BCM_E_XXX 589 */ 590 int 591 soc_esw_portctrl_setup_ext_phy_add(int unit, int port, portmod_pbmp_t *phy_ports) 592 { 593 int rv, chain_idx, first_port; 594 int pport; 595 uint8_t is_100G_port; 596 uint32 ext_phy_addr, xphy_gearbox_mode; 597 uint32 num_int_cores; 598 uint32 first_phy_lane[3]; 599 int phy_chain_length; 600 uint32 primary_core_num=0; 601 portmod_dispatch_type_t type; 602 soc_esw_portctrl_phy_toplogy_t topology; 603 soc_100g_lane_config_t lane_config; 604 605 phymod_core_access_t core_access; 606 phymod_ref_clk_t ref_clk; 607 phymod_firmware_load_method_t fw_load_method; 608 portmod_xphy_lane_connection_t xphy_lane_connection; 609 int xphy_idx = PORTMOD_XPHY_EXISTING_IDX; 610 611 /* add Ext Phy to portmod. */ 612 613 /* identify if the pport is part of 100G port and 12x10 PM 614 if true then get the mapping inf0 3:4:3 or 4:4:2 */ 615 lane_config = SOC_LANE_CONFIG_100G_4_4_2; 616 pport = 0; 617 is_100G_port = 0; 618 619 /* assumption is that first pport of the PM12x10 is 620 specified as a 100G port in portmap_lport=pport:100:map_info */ 621 PORTMOD_PBMP_ITER(*phy_ports, pport) { 622 623 rv = portmod_phy_pm_type_get(unit, pport, &type); 624 if (rv) return (rv); 625 626 /* 627 * Check to see if the port we are using is 100G or greater 628 * and is pm12x10 type 629 */ 630 #if defined(PORTMOD_PM12X10_XGS_SUPPORT) && defined(PORTMOD_PM12X10_SUPPORT) 631 if ( (type != portmodDispatchTypePm12x10) && (type != portmodDispatchTypePm12x10_xgs) ) { 632 continue; 633 } 634 #elif defined(PORTMOD_PM12X10_SUPPORT) 635 if ( (type != portmodDispatchTypePm12x10) ) { 636 continue; 637 } 638 #else 639 if ( (type != portmodDispatchTypeCount) ) { 640 continue; 641 } 642 #endif 643 644 645 if ((port != -1) && (SOC_INFO(unit).port_speed_max[port] >= 100000)) { 646 /* read the portmap config to get the map info */ 647 lane_config = SOC_INFO(unit).port_100g_lane_config[port]; 648 is_100G_port = 1; 649 } 650 } 651 652 653 pport = 0; 654 655 /* for each port in the input bit map read get the physical port number and call 656 the new config get function to identify the physical topology with the external phy */ 657 first_port = -1; 658 659 PORTMOD_PBMP_ITER(*phy_ports, pport) { 660 661 if (first_port == -1) first_port = pport; 662 663 /* breadth of the phy chain Assumption here is that all the physical ports in a 664 logical port will have same phy chain length */ 665 ext_phy_addr = 0xFF; 666 chain_idx = 0; 667 668 rv = soc_esw_portctrl_ext_phy_config_parameter_get(unit, port, 669 &ext_phy_addr, &num_int_cores, first_phy_lane); 670 phy_chain_length = soc_property_port_get(unit, port, spn_PHY_CHAIN_LENGTH, 0); 671 primary_core_num = soc_property_port_get(unit, ext_phy_addr, spn_XPHY_PRIMARY_CORE_NUM, ext_phy_addr); 672 xphy_gearbox_mode = soc_property_port_get(unit, port, spn_PHY_GEARBOX_ENABLE, 0); 673 674 while((ext_phy_addr != 0xFF) || (phy_chain_length != 0)) { 675 phy_chain_length = 0; 676 num_int_cores = 0; 677 678 chain_idx++; 679 680 portmod_xphy_lane_connection_t_init(unit, &xphy_lane_connection); 681 682 683 phy_chain_length = soc_property_port_get(unit, port, spn_PHY_CHAIN_LENGTH, 0); 684 685 /* phy chain length and ext_phy_addr configs for a port are mutually exclusive */ 686 if (phy_chain_length && (chain_idx > phy_chain_length)) break; 687 688 /* rv = soc_esw_portctrl_ext_phy_config_parameter_get(unit, xphy_logical_port, 689 &ext_phy_addr, &num_int_cores, first_phy_lane); 690 */ 691 topology.pport = pport; 692 topology.xphy_index = chain_idx; 693 topology.sys_lane = -1; 694 topology.line_lane = -1; 695 soc_esw_portctrl_ext_phy_config_topology_get(unit, &topology); 696 697 /* only for the iner most external phys we have an alternate config */ 698 xphy_lane_connection.ss_lane_mask = -1; 699 xphy_lane_connection.ls_lane_mask = -1; 700 if (topology.is_default && (chain_idx == 1)) { 701 topology.xphy_id = ext_phy_addr; 702 xphy_lane_connection.xphy_id = ext_phy_addr; 703 /* below logic should be applied only to inner most external phy*/ 704 if (is_100G_port) { 705 xphy_lane_connection.ss_lane_mask = 0x1 << (pport - first_port); 706 xphy_lane_connection.ls_lane_mask = 0x1 << (pport - first_port); 707 switch (lane_config) { 708 case SOC_LANE_CONFIG_100G_4_4_2: 709 if ((pport - first_port) == 10 || 710 (pport - first_port) == 11) { 711 xphy_lane_connection.ss_lane_mask = -1; 712 xphy_lane_connection.ls_lane_mask = -1; 713 } 714 /* Temp fix for sesto gearbox */ 715 if ((((pport - first_port) > 3) && 716 ((pport - first_port) < 8))) { 717 xphy_lane_connection.ls_lane_mask = 0x1 << ((pport - first_port)-4); 718 } else { 719 xphy_lane_connection.ls_lane_mask = -1; 720 } 721 722 break; 723 case SOC_LANE_CONFIG_100G_3_4_3: 724 if ((pport - first_port) == 3 || 725 (pport - first_port) == 11) { 726 xphy_lane_connection.ss_lane_mask = -1; 727 xphy_lane_connection.ls_lane_mask = -1; 728 } 729 if (((pport - first_port) > 3) && 730 ((pport - first_port) < 11)) { 731 xphy_lane_connection.ss_lane_mask = 0x1 << ((pport - first_port) - 1); 732 xphy_lane_connection.ls_lane_mask = 0x1 << ((pport - first_port) - 1); 733 } 734 /* Temp fix for sesto gearbox */ 735 if ((((pport - first_port) > 3) && 736 ((pport - first_port) < 8))) { 737 xphy_lane_connection.ls_lane_mask = 0x1 << ((pport - first_port)-4); 738 } else { 739 xphy_lane_connection.ls_lane_mask = -1; 740 } 741 742 743 break; 744 case SOC_LANE_CONFIG_100G_2_4_4: 745 if ((pport - first_port) == 2 || 746 (pport - first_port) == 3) { 747 xphy_lane_connection.ss_lane_mask = -1; 748 xphy_lane_connection.ls_lane_mask = -1; 749 } 750 if ((pport - first_port) > 3) { 751 xphy_lane_connection.ss_lane_mask = 0x1 << ((pport - first_port) - 2); 752 xphy_lane_connection.ls_lane_mask = 0x1 << ((pport - first_port) - 2); 753 } 754 /* Temp fix for sesto gearbox */ 755 if ((pport - first_port) > 5) { 756 xphy_lane_connection.ls_lane_mask = -1; 757 } 758 if ((((pport - first_port) > 3) && 759 ((pport - first_port) < 8))) { 760 xphy_lane_connection.ls_lane_mask = 0x1 << ((pport - first_port)-4); 761 } else { 762 xphy_lane_connection.ls_lane_mask = -1; 763 } 764 765 break; 766 default: 767 xphy_lane_connection.ss_lane_mask = 0x1 << (pport - first_port); 768 xphy_lane_connection.ls_lane_mask = 0x1 << (pport - first_port); 769 break; 770 } 771 /* if the system is on a Gearbox mode then line side port 772 beyond 3 should be set to -1 on an external phy */ 773 } else { 774 /* for non 100G port like 10G and 40G */ 775 /*This only support 2x25G to 4x10G gearbox.*/ 776 if(pport > 0){ 777 if (xphy_gearbox_mode) { 778 xphy_lane_connection.ss_lane_mask = 0x1 << ((pport - 1) % 4); 779 xphy_lane_connection.ls_lane_mask = 0x3 << (((pport - 1) % 4) * 2); 780 } else { 781 xphy_lane_connection.ss_lane_mask = 0x1 << ((pport - 1) % 4); 782 xphy_lane_connection.ls_lane_mask = 0x1 << ((pport - 1) % 4); 783 } 784 } 785 } 786 787 } else { 788 ext_phy_addr = topology.xphy_id; 789 xphy_lane_connection.xphy_id = topology.xphy_id; 790 if (topology.sys_lane != -1) { 791 xphy_lane_connection.ss_lane_mask = 0x1 << topology.sys_lane; 792 } else { 793 xphy_lane_connection.ss_lane_mask = -1; 794 } 795 if (topology.line_lane != -1) { 796 xphy_lane_connection.ls_lane_mask = 0x1 << topology.line_lane; 797 } else { 798 xphy_lane_connection.ls_lane_mask = -1; 799 } 800 } 801 802 if((PORTMOD_SUCCESS(rv)) && ((ext_phy_addr != 0xFF) || (phy_chain_length >= chain_idx))) { 803 804 /* get default xphy core_access and updated with xphy_addr. */ 805 soc_esw_portctrl_xphy_default_core_access_get(unit, &core_access); 806 core_access.access.addr = ext_phy_addr; 807 808 PORTMOD_IF_ERROR_RETURN(portmod_xphy_add(unit, ext_phy_addr, &core_access, &xphy_idx)); 809 810 /* if entry is not added, release user_acc from core_access. */ 811 if (xphy_idx == PORTMOD_XPHY_EXISTING_IDX){ 812 if (core_access.access.user_acc != NULL){ 813 sal_free(core_access.access.user_acc); 814 } 815 } else { 816 /* record the user_acc */ 817 portmod_chain_xphy_user_access_store(unit, xphy_idx, core_access.access.user_acc); 818 } 819 /* call external phy lane attach */ 820 portmod_xphy_lane_attach(unit, pport, topology.xphy_index, &xphy_lane_connection); 821 822 /* update the value from config */ 823 ref_clk = phymodRefClk156Mhz; 824 fw_load_method = phymodFirmwareLoadMethodExternal; 825 /* xphy_core_info. polarity*/ 826 PORTMOD_IF_ERROR_RETURN(portmod_xphy_primary_core_num_set(unit, ext_phy_addr, primary_core_num)); 827 PORTMOD_IF_ERROR_RETURN(portmod_xphy_ref_clk_set(unit, ext_phy_addr, ref_clk)); 828 PORTMOD_IF_ERROR_RETURN(portmod_xphy_fw_load_method_set(unit, ext_phy_addr, fw_load_method)); 829 soc_esw_portctrl_core_config_update(unit, port, pport, (pport - first_port), ext_phy_addr, chain_idx); 830 } 831 832 /* 833 * For only 1 ext phy allowd, if additional phy needed, need to parse the config 834 * to get external phy addr. 835 */ 836 ext_phy_addr = 0xFF; /* NO Additional PHY */ 837 } /* while each phy at index */ 838 } /* SOC_PBMP_ITER */ 839 return SOC_E_NONE; 840 } 841 842 843 844 /* 845 * Function: 846 * soc_esw_portctrl_reset_tsc0_cb 847 * Purpose: 848 * Reset TSC by setting TSC control register. 849 * Index 0 means TSC core index0, first TSC ctrl register index, 850 * which resides in PGW block. 851 * For TD2+ case, the register is PGW_TSC0_CTRL_REG 852 * Parameters: 853 * unit - (IN) Unit number. 854 * port - (IN) Port number. 855 * in_reset - (IN) reset status 856 * Returns: 857 * BCM_E_XXX 858 */ 859 int 860 soc_esw_portctrl_reset_tsc0_cb(int unit, int port, uint32 in_reset) 861 { 862 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_HURRICANE2_SUPPORT) || defined(BCM_SABER2_SUPPORT) 863 return (!in_reset? soc_tsc_xgxs_reset(unit, port, 0) : SOC_E_NONE); 864 #else 865 return SOC_E_NONE; 866 #endif 867 } 868 869 /* 870 * Function: 871 * soc_esw_portctrl_reset_tsc1_cb 872 * Purpose: 873 * Reset TSC by setting TSC control register. 874 * Index 1 means TSC core index1, 2nd TSC ctrl register index, 875 * which resides in PGW block. 876 * For TD2+ case, the register is PGW_TSC1_CTRL_REG 877 * Parameters: 878 * unit - (IN) Unit number. 879 * port - (IN) Port number. 880 * in_reset - (IN) reset status 881 * Returns: 882 * BCM_E_XXX 883 */ 884 int 885 soc_esw_portctrl_reset_tsc1_cb(int unit, int port, uint32 in_reset) 886 { 887 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_HURRICANE2_SUPPORT) || defined(BCM_SABER2_SUPPORT) 888 return (!in_reset? soc_tsc_xgxs_reset(unit, port, 1) : SOC_E_NONE); 889 #else 890 return SOC_E_NONE; 891 #endif 892 } 893 894 /* 895 * Function: 896 * soc_esw_portctrl_reset_tsc2_cb 897 * Purpose: 898 * Reset TSC by setting TSC control register. 899 * Index 2 means TSC core index2, 3rd TSC ctrl register index, 900 * which resides in PGW block. 901 * For TD2+ case, the register is PGW_TSC2_CTRL_REG 902 * Parameters: 903 * unit - (IN) Unit number. 904 * port - (IN) Port number. 905 * in_reset - (IN) reset status 906 * Returns: 907 * BCM_E_XXX 908 */ 909 int 910 soc_esw_portctrl_reset_tsc2_cb(int unit, int port, uint32 in_reset) 911 { 912 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_HURRICANE2_SUPPORT) || defined(BCM_SABER2_SUPPORT) 913 return (!in_reset? soc_tsc_xgxs_reset(unit, port, 2) : SOC_E_NONE); 914 #else 915 return SOC_E_NONE; 916 #endif 917 } 918 919 /* 920 * Function: 921 * soc_esw_portctrl_reset_tsc3_cb 922 * Purpose: 923 * Reset TSC by setting TSC control register. 924 * Index 3 means TSC core index3, 4th TSC ctrl register index, 925 * which resides in PGW block. 926 * For TD2+ case, the register is PGW_TSC3_CTRL_REG 927 * Parameters: 928 * unit - (IN) Unit number. 929 * port - (IN) Port number. 930 * in_reset - (IN) reset status 931 * Returns: 932 * BCM_E_XXX 933 */ 934 int 935 soc_esw_portctrl_reset_tsc3_cb(int unit, int port, uint32 in_reset) 936 { 937 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_HURRICANE2_SUPPORT) || defined(BCM_SABER2_SUPPORT) 938 return (!in_reset? soc_tsc_xgxs_reset(unit, port, 3) : SOC_E_NONE); 939 #else 940 return SOC_E_NONE; 941 #endif 942 } 943 944 #ifdef BCM_MONTEREY_SUPPORT 945 static int 946 _check_cpri_speed ( 947 int speedi, portmod_encap_t int_mode) 948 { 949 int speedo; 950 if(int_mode == _SHR_PORT_ENCAP_RSVD4) { 951 switch(speedi) { 952 case 3072: 953 speedo = cprimodRsvd4SpdMult4X; 954 break; 955 case 6144: 956 speedo = cprimodRsvd4SpdMult8X; 957 break; 958 default: 959 speedo = -1; 960 break; 961 } 962 } else if(int_mode == _SHR_PORT_ENCAP_CPRI) { 963 switch(speedi) { 964 case 1228: 965 speedo = cprimodSupportedSpd1228p8; 966 break; 967 case 2457: 968 speedo = cprimodSupportedSpd2457p6; 969 break; 970 case 3072: 971 speedo = cprimodSupportedSpd3072p0; 972 break; 973 case 4915: 974 speedo = cprimodSupportedSpd4915p2; 975 break; 976 case 6144: 977 speedo = cprimodSupportedSpd6144p0; 978 break; 979 case 9830: 980 speedo = cprimodSupportedSpd9830p4; 981 break; 982 case 10137: 983 speedo = cprimodSupportedSpd10137p6; 984 break; 985 case 12165: 986 speedo = cprimodSupportedSpd12165p12; 987 break; 988 case 24330: 989 speedo = cprimodSupportedSpd24330p24; 990 break; 991 default: 992 speedo = -1; 993 break; 994 } 995 } else { 996 speedo = -1; 997 } 998 return speedo; 999 } 1000 #endif 1001 1002 1003 1004 /* 1005 * Function: 1006 * soc_esw_portctrl_config_get 1007 * Purpose: 1008 * Get interface and initialization configuration 1009 * for given logical port. 1010 * Parameters: 1011 * unit - (IN) Unit number. 1012 * port - (IN) Logical port number. 1013 * interface_config - (IN/OUT) Port interface configuration. 1014 * init_config - (IN/OUT) Port initialization configuration. 1015 * Returns: 1016 * SOC_E_XXX 1017 */ 1018 int 1019 soc_esw_portctrl_config_get(int unit, soc_port_t port, 1020 portmod_port_interface_config_t* interface_config, 1021 portmod_port_init_config_t* init_config, 1022 phymod_operation_mode_t *phy_op_mode) 1023 { 1024 /* soc_port_if_t interface_type; */ 1025 int port_num_lanes, fiber_pref = 0, is_scrambler = 0, i; 1026 int fs_cl72=0, max_speed, speed; 1027 /* phymod_tx_t *p_tx; */ 1028 uint32 preemphasis=0xffffffff, driver_current=0xffffffff; 1029 uint32 port_preemphasis, port_driver_current; 1030 uint32 lane_preemphasis, lane_driver_current; 1031 /*int rxaui_mode = 0; */ 1032 int ref_clk_prop = 0, encap_mode; 1033 int adjust_num = 0; 1034 #ifdef BCM_MONTEREY_SUPPORT 1035 int port_speed_cpri = 0; 1036 int roe_speed_rsvd4, roe_speed_cpri; 1037 #endif 1038 1039 /* Initialize both interface config and init config */ 1040 PORTMOD_IF_ERROR_RETURN 1041 (portmod_port_init_config_t_init(unit, init_config)); 1042 PORTMOD_IF_ERROR_RETURN 1043 (portmod_port_interface_config_t_init(unit, interface_config)); 1044 1045 port_num_lanes = SOC_INFO(unit).port_num_lanes[port]; 1046 interface_config->port_num_lanes = port_num_lanes; 1047 1048 *phy_op_mode = soc_property_port_get(unit, port, spn_PHY_PCS_REPEATER, 1049 phymodOperationModeRetimer); 1050 1051 init_config->is_hg = (PBMP_MEMBER(SOC_HG2_PBM(unit), port) || 1052 PBMP_MEMBER(PBMP_HG_ALL(unit), port)); 1053 if (init_config->is_hg) { 1054 PHYMOD_INTF_MODES_HIGIG_SET(interface_config); 1055 } 1056 1057 fiber_pref = soc_property_port_get(unit, port, 1058 spn_SERDES_FIBER_PREF, fiber_pref); 1059 if (fiber_pref) { 1060 PHYMOD_INTF_MODES_FIBER_SET(interface_config); 1061 } 1062 1063 1064 1065 if (IS_C_PORT(unit, port) || 1066 (IS_CXX_PORT(unit, port) && IS_CL_PORT(unit, port))) { 1067 PHYMOD_INTF_MODES_TRIPLE_CORE_SET(interface_config); 1068 1069 switch(SOC_INFO(unit).port_100g_lane_config[port]) { 1070 case SOC_LANE_CONFIG_100G_4_4_2: 1071 PHYMOD_INTF_MODES_TC_442_SET(interface_config); 1072 break ; 1073 case SOC_LANE_CONFIG_100G_2_4_4: 1074 PHYMOD_INTF_MODES_TC_244_SET(interface_config); 1075 break ; 1076 case SOC_LANE_CONFIG_100G_3_4_3: 1077 PHYMOD_INTF_MODES_TC_343_SET(interface_config); 1078 break ; 1079 default: 1080 PHYMOD_INTF_MODES_TC_343_SET(interface_config); 1081 break ; 1082 } 1083 init_config->port_fallback_lane = 1084 SOC_INFO(unit).port_fallback_lane[port]; 1085 } 1086 1087 1088 /* Should be changed based on the speed later in the flow */ 1089 if (SOC_PBMP_MEMBER(SOC_PORT_DISABLED_BITMAP(unit,all), port)) 1090 interface_config->interface = SOC_PORT_IF_NULL; 1091 else 1092 interface_config->interface = soc_property_port_get(unit, port, 1093 spn_SERDES_IF_TYPE, 1094 SOC_PORT_IF_XFI); 1095 max_speed = SOC_INFO(unit).port_speed_max[port]; 1096 interface_config->max_speed = max_speed ; 1097 1098 /* Fill in init config */ 1099 init_config->an_cl37 = soc_property_port_get(unit, port, 1100 spn_PHY_AN_C37, 0); 1101 1102 /* default AN mode would be cl73 with no BAM */ 1103 init_config->an_cl73 = soc_property_port_get(unit, port, 1104 spn_PHY_AN_C73, PORTMOD_CL73_WO_BAM); 1105 init_config->cl37_sgmii_RESTART_CNT = soc_property_port_get(unit, port, 1106 spn_SERDES_CL37_SGMII_RESTART_COUNT, 1107 init_config->cl37_sgmii_RESTART_CNT); 1108 1109 init_config->an_master_lane = soc_property_port_get(unit, port, 1110 spn_PHY_AUTONEG_MASTER_LANE, 1111 0); 1112 1113 /* an_cl72 means whether to turn on CL72 when AN is on. Default value 1114 * should be 1 according to the IEEE spec. 1115 */ 1116 init_config->an_cl72 = soc_property_port_get(unit, port, 1117 spn_PHY_AN_C72, 1); 1118 1119 /* Get the timestamp adjust */ 1120 adjust_num = COUNTOF(ts_adjust_props); 1121 for (i = 0; i < adjust_num; i++) { 1122 init_config->port_ts_adjust[i].speed = ts_adjust_props[i].speed; 1123 init_config->port_ts_adjust[i].osts_adjust = soc_property_port_get(unit, port, ts_adjust_props[i].props[0], 0); 1124 init_config->port_ts_adjust[i].tsts_adjust = soc_property_port_get(unit, port, ts_adjust_props[i].props[1], 0); 1125 } 1126 1127 init_config->txpi_mode = soc_property_port_get(unit, port, spn_SERDES_TXPI_MODE, 0); 1128 init_config->txpi_sdm_scheme = soc_property_port_get(unit, port, spn_TXPI_SDM_SCHEME, 0); 1129 1130 #if 0 1131 if (SOC_IS_TOMAHAWKX(unit)) { 1132 if(an_cl73) { 1133 init_config->an_mode = 1134 ((an_cl73 == 1) ? phymod_AN_MODE_CL73 : phymod_AN_MODE_CL73BAM); 1135 init_config->an_cl72 = 1; 1136 } else if (an_cl37) { 1137 init_config->an_mode = 1138 ((an_cl37 == 1) ? phymod_AN_MODE_CL37BAM : phymod_AN_MODE_CL37); 1139 init_config->an_cl72 = 0; 1140 } else { 1141 /* in TH/TH2, only management ports are pm4x10, others are pm4x25 */ 1142 if (IS_MANAGEMENT_PORT(unit, port)) { 1143 init_config->an_mode = phymod_AN_MODE_CL37; 1144 init_config->an_cl72 = 0; 1145 } else { 1146 init_config->an_mode = 1147 ((is_hg) ? phymod_AN_MODE_CL73BAM : phymod_AN_MODE_CL73); 1148 init_config->an_cl72 = 1; 1149 } 1150 } 1151 } 1152 #endif 1153 1154 init_config->an_fec = soc_property_port_get(unit, port, 1155 spn_PHY_AN_FEC, 1156 init_config->an_fec); 1157 1158 init_config->serdes_fec_enable = soc_property_port_get(unit, port, 1159 spn_SERDES_FEC_ENABLE, 1160 init_config->serdes_fec_enable); 1161 1162 fs_cl72 = soc_property_port_get(unit, port, spn_PORT_INIT_CL72, 1163 fs_cl72); 1164 if(fs_cl72) { 1165 init_config->fs_cl72 = PHYMOD_INTF_F_CL72_REQUESTED_BY_CNFG ; 1166 } 1167 1168 speed = SOC_INFO(unit).port_init_speed[port] > 0 ? 1169 SOC_INFO(unit).port_init_speed[port] : 1170 SOC_INFO(unit).port_speed_max[port]; 1171 1172 /* TSCE:for the Dual lane 10G mode scrambler should be enabled 1173 * to get the link up. To interop with legacy devices like TD+ 1174 * that does not require scrambler at dual lane 10g mode 1175 * spn_SERDES_SCRAMBLER_ENABLE should be explicitly set to "0" from 1176 * the config 1177 */ 1178 is_scrambler = 0; 1179 if (port_num_lanes == 2 && speed == 10000) { 1180 is_scrambler = 1; 1181 } 1182 1183 is_scrambler = soc_property_port_get(unit, port, 1184 spn_SERDES_SCRAMBLER_ENABLE, is_scrambler); 1185 if (is_scrambler) { 1186 PHYMOD_INTF_MODES_SCR_SET(interface_config); 1187 } 1188 1189 1190 interface_config->speed = 1191 soc_property_port_get(unit, port, spn_PORT_INIT_SPEED, speed); 1192 1193 init_config->pll_divider_req = 1194 soc_property_port_get(unit, port, spn_XGXS_PHY_PLL_DIVIDER, 0xA); 1195 1196 #if (defined BCM_HELIX5_SUPPORT) || (defined BCM_MAVERICK2_SUPPORT) 1197 if (SOC_IS_HELIX5(unit) || 1198 (SOC_IS_MAVERICK2(unit) && SOC_INFO(unit).bandwidth == 2000000)) { 1199 init_config->serdes_1000x_at_25g_vco = 1; 1200 init_config->serdes_10g_at_25g_vco = 1; 1201 } 1202 #endif 1203 init_config->serdes_1000x_at_6250_vco = 1204 soc_property_port_get(unit, port, 1205 spn_SERDES_1000X_AT_6250_VCO, 1206 init_config->serdes_1000x_at_6250_vco); 1207 1208 init_config->serdes_1000x_at_12500_vco = 1209 soc_property_port_get(unit, port, 1210 spn_SERDES_1000X_AT_12500_VCO, 1211 init_config->serdes_1000x_at_12500_vco); 1212 1213 init_config->serdes_1000x_at_25g_vco = 1214 soc_property_port_get(unit, port, 1215 spn_SERDES_1000X_AT_25G_VCO, 1216 init_config->serdes_1000x_at_25g_vco); 1217 1218 init_config->serdes_10g_at_25g_vco = 1219 soc_property_port_get(unit, port, 1220 spn_SERDES_10G_AT_25G_VCO, 1221 init_config->serdes_10g_at_25g_vco); 1222 1223 if (init_config->serdes_1000x_at_12500_vco) { 1224 /* 1225 * VCO = (PLL_DIV) * (REF_CLK) 1226 * REF_CLK = 156.25 1227 * VCO = 12500 1228 * PLL_DIV = 80 1229 */ 1230 init_config->pll_divider_req = 80; 1231 interface_config->pll_divider_req = 80; 1232 } else if (init_config->serdes_1000x_at_6250_vco) { 1233 /* 1234 * VCO = (PLL_DIV) * (REF_CLK) 1235 * REF_CLK = 156.25 1236 * VCO = 6250 1237 * PLL_DIV = 40 1238 */ 1239 init_config->pll_divider_req = 40; 1240 interface_config->pll_divider_req = 40; 1241 } else if (init_config->serdes_1000x_at_25g_vco || 1242 init_config->serdes_10g_at_25g_vco) { 1243 /* 1244 * VCO = (PLL_DIV) * (REF_CLK) 1245 * REF_CLK = 156.25 1246 * VCO = 25G 1247 * PLL_DIV = 165 1248 */ 1249 init_config->pll_divider_req = 165; 1250 interface_config->pll_divider_req = 165; 1251 } 1252 init_config->cx4_10g = soc_property_port_get(unit, port, 1253 spn_10G_IS_CX4, TRUE); 1254 1255 SOC_IF_ERROR_RETURN(portmod_common_default_interface_get(interface_config)); 1256 1257 #ifdef BCM_HELIX5_SUPPORT 1258 /* HX5 supports QSGMII and USXGMII mode in Pm4x10_qtc core. */ 1259 if (SOC_IS_HELIX5(unit)) { 1260 int phy_port, base_port, port_gmii_mode; 1261 phy_port = SOC_INFO(unit).port_l2p_mapping[port]; 1262 if (SOC_PORT_BLOCK_TYPE(unit, phy_port) == SOC_BLK_GXPORT) { 1263 base_port = phy_port - (phy_port - 1) % 16; 1264 port_gmii_mode = soc_property_phys_port_get(unit, base_port, 1265 spn_PORT_GMII_MODE, 0); 1266 switch (port_gmii_mode) { 1267 case 0: 1268 init_config->qtc_mode = portmodQtcModeEthernet; 1269 break; 1270 case 1: 1271 init_config->qtc_mode = portmodQtcModeQsgmii; 1272 break; 1273 case 2: 1274 init_config->qtc_mode = portmodQtcModeUsxgmii; 1275 break; 1276 default: 1277 init_config->qtc_mode = portmodQtcModeInvalid; 1278 break; 1279 } 1280 if ((init_config->qtc_mode == portmodQtcModeQsgmii) || 1281 (init_config->qtc_mode == portmodQtcModeUsxgmii)) { 1282 interface_config->interface = SOC_PORT_IF_SGMII; 1283 } 1284 } 1285 } 1286 #endif 1287 1288 if (SOC_PBMP_MEMBER(SOC_PORT_DISABLED_BITMAP(unit,all), port)) 1289 interface_config->interface = SOC_PORT_IF_NULL; 1290 1291 /* get internal serdes preemphasis and current property */ 1292 port_preemphasis = 0xffffffff; 1293 port_driver_current = 0xffffffff; 1294 port_preemphasis = soc_property_port_get(unit, port, 1295 spn_SERDES_PREEMPHASIS, port_preemphasis); 1296 port_driver_current = soc_property_port_get(unit, port, 1297 spn_SERDES_DRIVER_CURRENT, 1298 port_driver_current); 1299 for (i=0; i<port_num_lanes; i++){ 1300 init_config->tx_params_user_flag[i] = 0; 1301 } 1302 for (i=0; i<port_num_lanes; i++){ 1303 lane_preemphasis = 0xffffffff; 1304 lane_preemphasis = soc_property_port_suffix_num_get(unit, port, i, 1305 spn_SERDES_PREEMPHASIS, "lane", lane_preemphasis); 1306 if (lane_preemphasis != 0xffffffff){ 1307 preemphasis = lane_preemphasis; 1308 }else if (port_preemphasis != 0xffffffff){ 1309 preemphasis = port_preemphasis; 1310 }else { 1311 preemphasis = 0xffffffff; 1312 } 1313 1314 if(preemphasis != 0xffffffff){ 1315 init_config->tx_params_user_flag[i] |= 1316 PORTMOD_USER_SET_TX_PREEMPHASIS_BY_CONFIG; 1317 init_config->tx_params[i].pre = preemphasis & 0xff; 1318 init_config->tx_params[i].main = (preemphasis & 0xff00) >> 8; 1319 init_config->tx_params[i].post = (preemphasis & 0xff0000) >> 16; 1320 } 1321 } 1322 for (i=0; i<port_num_lanes; i++){ 1323 lane_driver_current = 0xffffffff; 1324 lane_driver_current = soc_property_port_suffix_num_get(unit, port, i, 1325 spn_SERDES_DRIVER_CURRENT, "lane", lane_driver_current); 1326 if (lane_driver_current != 0xffffffff){ 1327 driver_current = lane_driver_current; 1328 }else if (port_driver_current != 0xffffffff){ 1329 driver_current = port_driver_current; 1330 }else { 1331 driver_current = 0xffffffff; 1332 } 1333 1334 if(driver_current != 0xffffffff){ 1335 init_config->tx_params_user_flag[i] |= PORTMOD_USER_SET_TX_AMP_BY_CONFIG; 1336 init_config->tx_params[i].amp = driver_current; 1337 } 1338 } 1339 1340 /* get external phy preemphasis and current property */ 1341 port_preemphasis = 0xffffffff; 1342 port_driver_current = 0xffffffff; 1343 port_preemphasis = soc_property_port_get(unit, port, 1344 spn_PHY_PREEMPHASIS, preemphasis); 1345 port_driver_current = soc_property_port_get(unit, port, 1346 spn_PHY_DRIVER_CURRENT, 1347 driver_current); 1348 for (i=0; i<port_num_lanes; i++){ 1349 init_config->ext_phy_tx_params_user_flag[i] = 0; 1350 } 1351 for (i=0; i<port_num_lanes; i++){ 1352 lane_preemphasis = 0xffffffff; 1353 lane_preemphasis = soc_property_port_suffix_num_get(unit, port, i, 1354 spn_PHY_PREEMPHASIS, "lane", lane_preemphasis); 1355 if (lane_preemphasis != 0xffffffff){ 1356 preemphasis = lane_preemphasis; 1357 }else if (port_preemphasis != 0xffffffff){ 1358 preemphasis = port_preemphasis; 1359 }else { 1360 preemphasis = 0xffffffff; 1361 } 1362 1363 if(preemphasis != 0xffffffff){ 1364 init_config->ext_phy_tx_params_user_flag[i] |= 1365 PORTMOD_USER_SET_TX_PREEMPHASIS_BY_CONFIG ; 1366 init_config->ext_phy_tx_params[i].pre = preemphasis & 0xff; 1367 init_config->ext_phy_tx_params[i].main = (preemphasis & 0xff00) >> 8; 1368 init_config->ext_phy_tx_params[i].post = (preemphasis & 0xff0000) >> 16; 1369 } 1370 } 1371 for (i=0; i<port_num_lanes; i++){ 1372 lane_driver_current = 0xffffffff; 1373 lane_driver_current = soc_property_port_suffix_num_get(unit, port, i, 1374 spn_PHY_DRIVER_CURRENT, "lane", lane_driver_current); 1375 if (lane_driver_current != 0xffffffff){ 1376 driver_current = lane_driver_current; 1377 }else if (port_driver_current != 0xffffffff){ 1378 driver_current = port_driver_current; 1379 }else { 1380 driver_current = 0xffffffff; 1381 } 1382 1383 if(driver_current != 0xffffffff){ 1384 init_config->ext_phy_tx_params_user_flag[i] |= PORTMOD_USER_SET_TX_AMP_BY_CONFIG; 1385 init_config->ext_phy_tx_params[i].amp = driver_current; 1386 } 1387 } 1388 1389 if ((SOC_PORTCTRL_FUNCTIONS(unit)) && 1390 (SOC_PORTCTRL_FUNCTIONS(unit)->soc_portctrl_pm_port_config_get)) { 1391 SOC_IF_ERROR_RETURN 1392 (SOC_PORTCTRL_FUNCTIONS(unit)->soc_portctrl_pm_port_config_get( 1393 unit, port, (portmod_port_init_config_t *)init_config)); 1394 } 1395 1396 ref_clk_prop = soc_property_port_get(unit, port, 1397 spn_XGXS_LCPLL_XTAL_REFCLK, 156); 1398 1399 if ((ref_clk_prop == 156) ||( ref_clk_prop == 0)) { 1400 init_config->ref_clk = phymodRefClk156Mhz; /**< 156.25MHz */ 1401 } else if (ref_clk_prop == 125) { 1402 init_config->ref_clk = phymodRefClk125Mhz; /**< 125MHz */ 1403 } else { 1404 LOG_ERROR(BSL_LS_SOC_PORT, 1405 (BSL_META_UP(unit, port, 1406 "ERROR: This %d MHz clk freq is not supported. Only 156 MHz and 125 MHz.\n"),ref_clk_prop)); 1407 } 1408 init_config->ref_clk_overwrite = 1; 1409 1410 /* Internal Serdes interface setting if user want to overwrite. */ 1411 interface_config->serdes_interface = 1412 soc_property_port_get(unit, port, spn_SERDES_IF_TYPE, 1413 SOC_PORT_IF_NULL); 1414 1415 if (IS_HG_PORT(unit, port)) { 1416 if (soc_feature(unit, soc_feature_no_higig_plus)) { 1417 encap_mode = SOC_ENCAP_HIGIG2; 1418 } else { 1419 encap_mode = soc_property_port_get(unit, port, 1420 spn_HIGIG2_HDR_MODE, 0) ? 1421 SOC_ENCAP_HIGIG2 : SOC_ENCAP_HIGIG; 1422 } 1423 interface_config->encap_mode = encap_mode; 1424 } 1425 #ifdef BCM_MONTEREY_SUPPORT 1426 if (IS_CPRI_PORT(unit, port)) { 1427 port_speed_cpri = _check_cpri_speed(SOC_INFO(unit).port_init_speed[port], _SHR_PORT_ENCAP_CPRI); 1428 if(port_speed_cpri >= 0) { 1429 if (IS_RSVD4_PORT(unit, port)) { 1430 roe_speed_rsvd4 = _check_cpri_speed(SOC_INFO(unit).port_init_speed[port], _SHR_PORT_ENCAP_RSVD4); 1431 roe_speed_cpri = -1; 1432 } else { 1433 roe_speed_cpri = _check_cpri_speed(SOC_INFO(unit).port_init_speed[port], _SHR_PORT_ENCAP_CPRI); 1434 roe_speed_rsvd4 = -1; 1435 } 1436 } else { 1437 roe_speed_cpri = soc_property_port_get(unit, port, spn_CPRI_PORT_INIT_SPEED_ID, -1); 1438 roe_speed_rsvd4 = soc_property_port_get(unit, port, spn_RSVD4_PORT_INIT_SPEED_ID, -1); 1439 } 1440 if ((roe_speed_cpri == -1)&&(roe_speed_rsvd4 == -1)) { 1441 LOG_WARN(BSL_LS_SOC_PORT, 1442 (BSL_META_UP(unit, port, 1443 "WARNING: For cpri port speed is not specified moving to 1228.8 M speed\n"))); 1444 roe_speed_cpri = 0; 1445 } 1446 if ((roe_speed_cpri != -1)&&(roe_speed_rsvd4 != -1)) { 1447 LOG_ERROR(BSL_LS_SOC_PORT, (BSL_META_UP(unit, port, 1448 "ERROR: For cpri port : two speeds are specified : can not have cpri_port_init_speed_id_%d and rsvd4_port_init_speed_id_%d on same port\n"), port, port)); 1449 return SOC_E_PARAM; 1450 } 1451 if (roe_speed_cpri != -1) { 1452 interface_config->encap_mode = _SHR_PORT_ENCAP_CPRI; 1453 interface_config->speed = roe_speed_cpri; 1454 } else if (roe_speed_rsvd4 != -1) { 1455 interface_config->encap_mode = _SHR_PORT_ENCAP_RSVD4; 1456 interface_config->speed = roe_speed_rsvd4; 1457 } 1458 init_config->roe_reserved_bit = soc_property_port_get(unit, port, 1459 spn_ROE_RESERVED_BIT, 0); 1460 init_config->roe_stuffing_bit= soc_property_port_get(unit, port, 1461 spn_ROE_STUFFING_BIT, 0); 1462 interface_config->serdes_scrambler_seed = soc_property_port_get(unit, port, 1463 spn_SERDES_SCRAMBLER_SEED, 0x55); 1464 interface_config->serdes_scrambler_enable = soc_property_port_get(unit, port, 1465 spn_SERDES_SCRAMBLER_ENABLE, 0); 1466 } 1467 #endif 1468 init_config->parity_enable = soc_property_port_get(unit, port, 1469 spn_PARITY_ENABLE, 0); 1470 1471 1472 interface_config->port_op_mode = 1473 soc_property_port_get(unit, port, spn_PHY_PCS_REPEATER, TRUE); 1474 1475 return SOC_E_NONE; 1476 } 1477 1478 1479 /* 1480 * Function: 1481 * soc_portctrl_pm_portmod_init 1482 * 1483 * Purpose: 1484 * Call device specific portmod init function 1485 * 1486 * Parameters: 1487 * unit - (IN) Unit number. 1488 * Returns: 1489 * SOC_E_UNAVAIL : if fuction vector is not correctly set 1490 * rv : return rv 1491 */ 1492 STATIC int 1493 soc_portctrl_pm_portmod_init(int unit) 1494 { 1495 int rv = SOC_E_NONE; 1496 1497 if ((SOC_PORTCTRL_FUNCTIONS(unit)) && 1498 (SOC_PORTCTRL_FUNCTIONS(unit)->soc_portctrl_pm_init)) { 1499 rv = SOC_PORTCTRL_FUNCTIONS(unit)->soc_portctrl_pm_init(unit); 1500 } else { 1501 rv = SOC_E_UNAVAIL; 1502 } 1503 return rv; 1504 } 1505 1506 /* 1507 * Function: 1508 * soc_portctrl_pm_portmod_deinit 1509 * 1510 * Purpose: 1511 * Call device specific portmod deinit function 1512 * 1513 * Parameters: 1514 * unit - (IN) Unit number. 1515 * Returns: 1516 * SOC_E_UNAVAIL : if fuction vector is not correctly set 1517 * rv : return rv 1518 */ 1519 STATIC int 1520 soc_portctrl_pm_portmod_deinit(int unit) 1521 { 1522 int rv = SOC_E_NONE; 1523 1524 if ((SOC_PORTCTRL_FUNCTIONS(unit)) && 1525 (SOC_PORTCTRL_FUNCTIONS(unit)->soc_portctrl_pm_deinit)) { 1526 rv = SOC_PORTCTRL_FUNCTIONS(unit)->soc_portctrl_pm_deinit(unit); 1527 } else { 1528 rv = SOC_E_UNAVAIL; 1529 } 1530 return rv; 1531 } 1532 1533 /* 1534 * Function: 1535 * soc_portctrl_pm_type_get 1536 * 1537 * Purpose: 1538 * Call device specific portmod pm_type get function 1539 * 1540 * Parameters: 1541 * unit - (IN) Unit number. 1542 * phy_port - (IN) Physical port. 1543 * pm_type - (OUT) pm_type 1544 * Returns: 1545 * SOC_E_UNAVAIL : if fuction vector is not correctly set 1546 * rv : return rv 1547 */ 1548 int 1549 soc_portctrl_pm_type_get(int unit, soc_port_t phy_port, 1550 int* pm_type) 1551 { 1552 int rv = SOC_E_NONE; 1553 1554 if ((SOC_PORTCTRL_FUNCTIONS(unit)) && 1555 (SOC_PORTCTRL_FUNCTIONS(unit)->soc_portctrl_pm_type_get)) { 1556 rv = SOC_PORTCTRL_FUNCTIONS(unit)->soc_portctrl_pm_type_get( 1557 unit, phy_port, pm_type); 1558 } else { 1559 rv = SOC_E_UNAVAIL; 1560 } 1561 return rv; 1562 } 1563 1564 1565 extern soc_portctrl_functions_t soc_td2p_portctrl_func; 1566 extern soc_portctrl_functions_t soc_th_portctrl_func; 1567 extern soc_portctrl_functions_t soc_gh_portctrl_func; 1568 extern soc_portctrl_functions_t soc_ap_portctrl_func; 1569 extern soc_portctrl_functions_t soc_hr3_portctrl_func; 1570 extern soc_portctrl_functions_t soc_mn_portctrl_func; 1571 extern soc_portctrl_functions_t soc_th2_portctrl_func; 1572 extern soc_portctrl_functions_t soc_th3_portctrl_func; 1573 extern soc_portctrl_functions_t soc_hx5_portctrl_func; 1574 1575 /* 1576 * Function: 1577 * soc_portctrl_functions_register 1578 * 1579 * Purpose: 1580 * This will set given function vector to soc_control->soc_portctrl_functions 1581 * 1582 * Parameters: 1583 * unit - (IN) Unit number. 1584 * func - (IN) device specific portctrl function vectors 1585 * Returns: 1586 * SOC_E_NONE 1587 */ 1588 int 1589 soc_esw_portctrl_functions_register(int unit, soc_driver_t *drv) 1590 { 1591 switch (drv->type) { 1592 #ifdef BCM_MAVERICK2_SUPPORT 1593 case SOC_CHIP_BCM56770_A0: 1594 case SOC_CHIP_BCM56771_A0: 1595 SOC_PORTCTRL_FUNCTIONS(unit) = &soc_mv2_portctrl_func; 1596 break; 1597 #endif 1598 #ifdef BCM_HELIX5_SUPPORT 1599 case SOC_CHIP_BCM56370_A0: 1600 SOC_PORTCTRL_FUNCTIONS(unit) = &soc_hx5_portctrl_func; 1601 break; 1602 #endif 1603 #ifdef BCM_TRIDENT3_SUPPORT 1604 case SOC_CHIP_BCM56870_A0: 1605 case SOC_CHIP_BCM56873_A0: 1606 SOC_PORTCTRL_FUNCTIONS(unit) = &soc_td3_portctrl_func; 1607 break; 1608 #endif 1609 #ifdef BCM_TRIDENT2PLUS_SUPPORT 1610 case SOC_CHIP_BCM56860_A0: 1611 SOC_PORTCTRL_FUNCTIONS(unit) = &soc_td2p_portctrl_func; 1612 break; 1613 #endif 1614 #ifdef BCM_TOMAHAWK_SUPPORT 1615 case SOC_CHIP_BCM56960_A0: 1616 SOC_PORTCTRL_FUNCTIONS(unit) = &soc_th_portctrl_func; 1617 break; 1618 #endif 1619 #ifdef BCM_GREYHOUND_SUPPORT 1620 case SOC_CHIP_BCM53400_A0: 1621 SOC_PORTCTRL_FUNCTIONS(unit) = &soc_gh_portctrl_func; 1622 break; 1623 #endif 1624 #ifdef BCM_APACHE_SUPPORT 1625 case SOC_CHIP_BCM56560_A0: 1626 case SOC_CHIP_BCM56560_B0: 1627 SOC_PORTCTRL_FUNCTIONS(unit) = &soc_ap_portctrl_func; 1628 break; 1629 #endif 1630 #ifdef BCM_MONTEREY_SUPPORT 1631 case SOC_CHIP_BCM56670_A0: 1632 case SOC_CHIP_BCM56670_B0: 1633 SOC_PORTCTRL_FUNCTIONS(unit) = &soc_mn_portctrl_func; 1634 break; 1635 #endif 1636 #ifdef BCM_TOMAHAWK2_SUPPORT 1637 case SOC_CHIP_BCM56970_A0: 1638 SOC_PORTCTRL_FUNCTIONS(unit) = &soc_th2_portctrl_func; 1639 break; 1640 #endif 1641 #ifdef BCM_TOMAHAWK3_SUPPORT 1642 case SOC_CHIP_BCM56980_A0: 1643 case SOC_CHIP_BCM56980_B0: 1644 SOC_PORTCTRL_FUNCTIONS(unit) = &soc_th3_portctrl_func; 1645 break; 1646 #endif 1647 default: 1648 break; 1649 } 1650 return SOC_E_NONE; 1651 } 1652 1653 /* 1654 * Function: 1655 * soc_portctrl_xport_type_verify 1656 * Purpose: 1657 * Check if the encapsulation is changed from configured selection. 1658 * Update the SOC port data structures to match the HW encapsulation selection. 1659 * Parameters: 1660 * unit - XGS unit #. 1661 * Returns: 1662 * SOC_E_XXX 1663 * Notes: 1664 * WARM_BOOT mode only 1665 */ 1666 STATIC int 1667 soc_portctrl_xport_type_verify(int unit) 1668 { 1669 int mode; 1670 soc_port_t port; 1671 1672 PBMP_PORT_ITER(unit, port) { 1673 SOC_IF_ERROR_RETURN(soc_esw_portctrl_encap_get(unit, port, &mode)); 1674 1675 if ((IS_XE_PORT(unit, port) || IS_CE_PORT(unit, port)) 1676 && (mode != SOC_ENCAP_IEEE)) { 1677 if (mode == SOC_ENCAP_CPRI || mode == SOC_ENCAP_RSVD4) { 1678 soc_xport_type_update(unit, port, mode); 1679 } else { 1680 soc_xport_type_update(unit, port, TRUE); 1681 } 1682 } else if (IS_HG_PORT(unit, port)) { 1683 if (mode == SOC_ENCAP_IEEE) { 1684 soc_xport_type_update(unit, port, FALSE); 1685 } else if (mode == SOC_ENCAP_CPRI || mode == SOC_ENCAP_RSVD4) { 1686 soc_xport_type_update(unit, port, mode); 1687 } 1688 } else if (IS_CPRI_PORT(unit, port) && (mode != SOC_ENCAP_CPRI)) { 1689 1690 if ( mode == SOC_ENCAP_RSVD4) { 1691 soc_xport_type_update(unit, port, mode); 1692 } else if (mode == SOC_ENCAP_IEEE) { 1693 soc_xport_type_update(unit, port, FALSE); 1694 } else { 1695 soc_xport_type_update(unit, port,TRUE); 1696 } 1697 } else if (IS_RSVD4_PORT(unit, port) && (mode != SOC_ENCAP_RSVD4)) { 1698 if ( mode == SOC_ENCAP_CPRI) { 1699 soc_xport_type_update(unit, port, mode); 1700 } else if (mode == SOC_ENCAP_IEEE) { 1701 soc_xport_type_update(unit, port, FALSE); 1702 } else { 1703 soc_xport_type_update(unit, port,TRUE); 1704 } 1705 } 1706 1707 1708 if (mode == SOC_ENCAP_HIGIG2) { 1709 if (IS_HG_PORT(unit, port)) { 1710 SOC_HG2_ENABLED_PORT_ADD(unit, port); 1711 } else { 1712 /* This should not happen */ 1713 return SOC_E_INTERNAL; 1714 } 1715 } 1716 } 1717 1718 return SOC_E_NONE; 1719 } 1720 1721 /* 1722 * Function: 1723 * soc_portctrl_phy_lane_config_fill 1724 * Purpose: 1725 * Parses the serdes_lane_config soc property's suffixes to fill in the 1726 * integer that's sent to portmod 1727 * Parameters: 1728 * unit - XGS unit #. 1729 * port - port of config being parsed 1730 * speed_config - pointer to structure containing the int being filled out 1731 * Returns: 1732 * SOC_E_XXX 1733 * Notes: 1734 */ 1735 STATIC int 1736 _soc_portctrl_phy_lane_config_fill(int unit, soc_port_t port, void *speed_config) 1737 { 1738 #ifdef PORTMOD_SUPPORT 1739 int dfe = 1; 1740 int dfe_lp = 0; 1741 char *dfe_str; 1742 char *dfe_types[] = {"off", "on", "lp", NULL}; 1743 int unreliable_los; 1744 int cl72_auto_polarity_en; 1745 int cl72_restart_timeout_en; 1746 int force_nr = 1; 1747 int force_er = 0; 1748 char *channel_mode_str; 1749 char *channel_mode_types[] = {"force_nr", "force_er", NULL}; 1750 int lp_has_prec_en; 1751 int default_lane_config = 0; 1752 int i, found_valid; 1753 int media_type_int = 0; 1754 char *media_type; 1755 char *media_types[] = {"backplane", "copper", "optics", NULL}; 1756 portmod_speed_config_t *config = (portmod_speed_config_t *)speed_config; 1757 1758 /* fetch values from config file if user filled them in */ 1759 dfe_str = soc_property_port_suffix_num_get_str(unit, port, 0, 1760 spn_SERDES_LANE_CONFIG, "dfe"); 1761 1762 if (dfe_str != NULL) { 1763 found_valid = 0; 1764 for (i = 0; dfe_types[i] != NULL; i++) { 1765 if (!sal_strncmp(dfe_types[i], dfe_str, 1766 sal_strlen(dfe_types[i]))) { 1767 switch(i) { 1768 case 0: 1769 dfe = 0; 1770 dfe_lp = 0; 1771 found_valid = 1; 1772 break; 1773 case 1: 1774 dfe = 1; 1775 dfe_lp = 0; 1776 found_valid = 1; 1777 break; 1778 case 2: 1779 dfe = 1; 1780 dfe_lp = 1; 1781 found_valid = 1; 1782 break; 1783 default: 1784 return SOC_E_INTERNAL; 1785 } 1786 } 1787 } 1788 1789 if (found_valid == 0) { 1790 return SOC_E_CONFIG; 1791 } 1792 } 1793 1794 media_type = soc_property_port_suffix_num_get_str(unit, port, 0, 1795 spn_SERDES_LANE_CONFIG, "media_type"); 1796 1797 /* get the media type integer from the string */ 1798 if (media_type != NULL) { 1799 found_valid = 0; 1800 for (i = 0; media_types[i] != NULL; i++) { 1801 if (!sal_strncmp(media_types[i], media_type, 1802 sal_strlen(media_types[i]))) { 1803 media_type_int = i; 1804 found_valid = 1; 1805 break; 1806 } 1807 } 1808 if (found_valid == 0) { 1809 return SOC_E_CONFIG; 1810 } 1811 } 1812 1813 unreliable_los = soc_property_port_suffix_num_get(unit, port, 0, 1814 spn_SERDES_LANE_CONFIG, "unreliable_los", 0); 1815 1816 cl72_auto_polarity_en = 1817 soc_property_port_suffix_num_get(unit, port, 0, 1818 spn_SERDES_LANE_CONFIG, "cl72_auto_polarity_en", 1819 0); 1820 1821 cl72_restart_timeout_en = 1822 soc_property_port_suffix_num_get(unit, port, 0, 1823 spn_SERDES_LANE_CONFIG, "cl72_restart_timeout_en", 1824 0); 1825 1826 channel_mode_str = soc_property_port_suffix_num_get_str(unit, port, 0, 1827 spn_SERDES_LANE_CONFIG, "channel_mode"); 1828 1829 if (channel_mode_str != NULL) { 1830 found_valid = 0; 1831 for (i = 0; channel_mode_types[i] != NULL; i++) { 1832 if (!sal_strncmp(channel_mode_types[i], channel_mode_str, 1833 sal_strlen(channel_mode_types[i]))) { 1834 switch(i) { 1835 case 0: 1836 force_er = 0; 1837 force_nr = 1; 1838 found_valid = 1; 1839 break; 1840 case 1: 1841 force_er = 1; 1842 force_nr = 0; 1843 found_valid = 1; 1844 break; 1845 default: 1846 return SOC_E_INTERNAL; 1847 } 1848 break; 1849 } 1850 } 1851 if (found_valid == 0) { 1852 return SOC_E_CONFIG; 1853 } 1854 } 1855 1856 1857 lp_has_prec_en = soc_property_port_suffix_num_get(unit, port, 0, 1858 spn_SERDES_LANE_CONFIG, "lp_has_prec_en", 0); 1859 1860 /* first set it to the default values */ 1861 config->lane_config = default_lane_config; 1862 1863 /* Insert the modified values into the phy lane config */ 1864 config->lane_config |= ((dfe & 0x1) << 2); 1865 config->lane_config |= ((dfe_lp & 0x1) << 3); 1866 config->lane_config |= ((media_type_int & 0x3) << 5); 1867 config->lane_config |= ((unreliable_los & 0x1) << 7); 1868 config->lane_config |= ((cl72_auto_polarity_en & 0x1) << 9); 1869 config->lane_config |= ((cl72_restart_timeout_en & 0x1) << 10); 1870 config->lane_config |= ((force_nr & 0x1) << 12); 1871 config->lane_config |= ((force_er & 0x1) << 11); 1872 config->lane_config |= ((lp_has_prec_en & 0x1) << 13); 1873 1874 return SOC_E_NONE; 1875 #else 1876 return SOC_E_UNAVAIL; 1877 #endif 1878 } 1879 1880 /* 1881 * Function: 1882 * soc_esw_portctrl_speed_config_fill 1883 * Purpose: This function fills in the speed_config structure for portmod. 1884 * Starting with PM8x50, the port macro needs this information to 1885 * set the speed of a port. 1886 * 1887 * NOTE: If speed, num_lane, fec, link_training, or lane_config are 1888 * passed as -1 parameters, then "default" values will be used. 1889 * 1890 * For fec, link_training and lane_config, their values will 1891 * try to be read from the config file first. 1892 * 1893 * Otherwise, if those parameters are >= 0, they will be used. 1894 * 1895 * Parameters: 1896 * unit - (IN) Unit number. 1897 * port - (IN) logical port 1898 * speed - (IN) Port Speed 1899 * num_lane - (IN) Number of lanes for port 1900 * fec - (IN) Forward Error Correction 1901 * link_training - (IN) link training field 1902 * lane_config - (IN) lane config field 1903 * speed_config - (OUT) the speed config structure to pass to portmod 1904 * 1905 * Returns: SOC_E_X 1906 */ 1907 int 1908 soc_esw_portctrl_speed_config_fill(int unit, soc_port_t port, 1909 int speed, 1910 int num_lane, 1911 int fec, 1912 int link_training, 1913 int lane_config, 1914 void *speed_config) 1915 { 1916 #ifdef PORTMOD_SUPPORT 1917 soc_info_t *si = &SOC_INFO(unit); 1918 portmod_speed_config_t *config = (portmod_speed_config_t *)speed_config; 1919 1920 if (speed >= 0) { 1921 config->speed = speed; 1922 } else { 1923 if (!SOC_PBMP_PORT_VALID(port) || IS_CPU_PORT(unit, port) || 1924 IS_MANAGEMENT_PORT(unit, port) || IS_LB_PORT(unit, port)) { 1925 return SOC_E_PARAM; 1926 } 1927 config->speed = si->port_speed_max[port]; 1928 } 1929 1930 if (num_lane >= 0) { 1931 config->num_lane = num_lane; 1932 } else { 1933 if (!SOC_PBMP_PORT_VALID(port) || IS_CPU_PORT(unit, port) || 1934 IS_MANAGEMENT_PORT(unit, port) || IS_LB_PORT(unit, port)) { 1935 return SOC_E_PARAM; 1936 } 1937 config->num_lane = si->port_num_lanes[port]; 1938 } 1939 1940 if (fec >= 0) { 1941 config->fec = fec; 1942 } else { 1943 if (!SOC_PBMP_PORT_VALID(port) || IS_CPU_PORT(unit, port) || 1944 IS_MANAGEMENT_PORT(unit, port) || IS_LB_PORT(unit, port)) { 1945 return SOC_E_PARAM; 1946 } 1947 1948 /* Read in FEC from config file if it was specified */ 1949 fec = soc_property_port_get(unit, port, spn_PORT_FEC, -1); 1950 1951 if (fec >= 0) { 1952 /* Mapping user config 'port_fec' to soc_port_phy_fec_t */ 1953 switch (fec) { 1954 case 0: 1955 config->fec = (portmod_fec_t)socPortPhyFecNone; 1956 break; 1957 case 1: 1958 config->fec = (portmod_fec_t)socPortPhyFecBaseR; 1959 break; 1960 case 2: 1961 config->fec = (portmod_fec_t)socPortPhyFecRsFec; 1962 break; 1963 case 3: 1964 config->fec = (portmod_fec_t)socPortPhyFecRs544; 1965 break; 1966 case 4: 1967 config->fec = (portmod_fec_t)socPortPhyFecRs272; 1968 break; 1969 case 9: 1970 config->fec = (portmod_fec_t)socPortPhyFecRs544_2xN; 1971 break; 1972 case 10: 1973 config->fec = (portmod_fec_t)socPortPhyFecRs272_2xN; 1974 break; 1975 default: 1976 return SOC_E_CONFIG; 1977 } 1978 } else { 1979 /* Don't ever let FEC be invalid */ 1980 /* 400G requires RS 544, so default to that */ 1981 if (config->speed == 400000) { 1982 config->fec = (portmod_fec_t)socPortPhyFecRs544_2xN; 1983 /* Default to no FEC if speed is not 400G */ 1984 } else if ((config->speed == 50000) && (config->num_lane == 1)) { 1985 config->fec = (portmod_fec_t)socPortPhyFecRs544; 1986 } else { 1987 config->fec = (portmod_fec_t)socPortPhyFecNone; 1988 } 1989 } 1990 } 1991 1992 if (link_training >= 0) { 1993 config->link_training = link_training; 1994 } else { 1995 if (!SOC_PBMP_PORT_VALID(port) || IS_CPU_PORT(unit, port) || 1996 IS_MANAGEMENT_PORT(unit, port) || IS_LB_PORT(unit, port)) { 1997 return SOC_E_PARAM; 1998 } 1999 config->link_training = 2000 soc_property_port_get(unit, port, spn_PORT_INIT_CL72, 0); 2001 } 2002 2003 if (lane_config >= 0) { 2004 config->lane_config = lane_config; 2005 } else if (lane_config == -2) { 2006 /* User passed in "auto" for lane config, so pass it in to portmod */ 2007 config->lane_config = -1; 2008 } else { 2009 /* Use config file values */ 2010 if (!SOC_PBMP_PORT_VALID(port) || IS_CPU_PORT(unit, port) || 2011 IS_MANAGEMENT_PORT(unit, port) || IS_LB_PORT(unit, port)) { 2012 return SOC_E_PARAM; 2013 } else { 2014 SOC_IF_ERROR_RETURN( 2015 _soc_portctrl_phy_lane_config_fill(unit, port, config)); 2016 } 2017 } 2018 2019 return SOC_E_NONE; 2020 #else 2021 return SOC_E_UNAVAIL; 2022 #endif /* PORTMOD_SUPPORT */ 2023 } 2024 2025 /* 2026 * Function: 2027 * soc_esw_portctrl_pm_update_vco_soc_info 2028 * Purpose: 2029 * The PM8x50 has 3 VCOs and a FEC type to select from that determine 2030 * the speed of the ports in use for each individual port macro. These 2031 * VCOs are determined by the port's speed, the number of lanes and FEC 2032 * used. 2033 * 2034 * Example (Different use of FEC may impact the VCO. 50G IEEE mode uses 2035 * PAM-4, but 50G BRCM mode 25G-NRZ): 2036 * 400G - 8 x 50G => PAM-4 2037 * 200G - 4 x 50G => PAM-4 2038 * 100G - 2 x 50G => PAM-4 2039 * 100G - 4 x 25G => 25G-NRZ 2040 * 50G - 1 x 50G => PAM-4 2041 * 50G - 2 x 25G => 25G-NRZ 2042 * 40G - 4 x 10G => 10G-NRZ 2043 * 25G - 1 x 25G => 25G-NRZ 2044 * 10G - 1 x 10G => 10G-NRZ 2045 * 2046 * The FEC type can be derived from the config file 2047 * 2048 * This function accepts the parameters below because the parameters 2049 * may be coming from SOC_INFO during init or from a 2050 * soc_port_schedule_state_t datatype during flexport. 2051 * 2052 * This function modifies the soc_info fields tvco and ovco for the 2053 * specified pm_id 2054 * 2055 * Parameters: 2056 * unit - (IN) Unit number. 2057 * phy_ports - (IN) array of physical ports corresponding to ONE 2058 * PM8x50 2059 * num_ports - (IN) Number of ports in the array 2060 * flags - (IN) Flags passed in to Portmod 2061 * Returns: SOC_E_X 2062 * 2063 * NOTE: PORTCTRL does not need to be initialized to use this function. 2064 * However, SOC_INFO must have parsed the config file in port_config_init. 2065 * 2066 * This is only called at init! 2067 */ 2068 int 2069 soc_esw_portctrl_pm_update_vco_soc_info(int unit, 2070 const int *phy_ports, 2071 int num_ports, 2072 int pm_id, 2073 portmod_dispatch_type_t pm_type, 2074 uint32 flags) 2075 { 2076 int port; 2077 int num_speeds = 0; 2078 int rv; 2079 int i, j; 2080 int *starting_lane_list; 2081 int *speed_for_pcs_bypass_port = NULL; 2082 portmod_pm_vco_setting_t vco_setting; 2083 portmod_speed_config_t speed_config_temp; 2084 portmod_speed_config_t *speed_config_list = NULL; 2085 2086 soc_info_t * si = &SOC_INFO(unit); 2087 rv = SOC_E_NONE; 2088 2089 /* This was designed with the PM8x50 in mind. Function needs updating if used for 2090 * a different PM */ 2091 #ifdef PORTMOD_PM8X50_SUPPORT 2092 if (pm_type != portmodDispatchTypePm8x50) { 2093 rv = SOC_E_UNAVAIL; 2094 LOG_WARN(BSL_LS_SOC_PORT, 2095 (BSL_META_U(unit, 2096 "%s: found a different PM than PM8x50 %d\n"), 2097 __FUNCTION__, rv)); 2098 return rv; 2099 } 2100 #endif 2101 2102 /* Find the port speeds in this PM */ 2103 /* allocate space for the speeds we're sending to portmod */ 2104 speed_config_list = sal_alloc(sizeof(portmod_speed_config_t) * num_ports, 2105 "speed_config_list"); 2106 /* 2107 * Allocate space for flag that indicates if the 2108 * speed is for PCS bypass port. 2109 */ 2110 speed_for_pcs_bypass_port = sal_alloc(sizeof(int) * num_ports, 2111 "speed_for_pcs_bypass_port"); 2112 starting_lane_list = sal_alloc(sizeof(int) * num_ports, 2113 "starting_lane_list"); 2114 2115 if (speed_config_list == NULL) { 2116 rv = SOC_E_MEMORY; 2117 goto vco_cleanup; 2118 } 2119 if (speed_for_pcs_bypass_port == NULL) { 2120 rv = SOC_E_MEMORY; 2121 goto vco_cleanup; 2122 } 2123 if (starting_lane_list == NULL) { 2124 rv = SOC_E_MEMORY; 2125 goto vco_cleanup; 2126 } 2127 2128 sal_memset(speed_config_list, 0, 2129 sizeof(portmod_speed_config_t) * num_ports); 2130 sal_memset(speed_for_pcs_bypass_port, 0, sizeof(int) * num_ports); 2131 sal_memset(starting_lane_list, 0, sizeof(int) * num_ports); 2132 2133 for (i = 0; i < num_ports; i++) { 2134 port = si->port_p2l_mapping[phy_ports[i]]; 2135 2136 /* if port is unmapped */ 2137 if (port == -1) { 2138 continue; 2139 } 2140 2141 sal_memset(&speed_config_temp, 0, sizeof(portmod_speed_config_t)); 2142 2143 /* If we're doing warmboot, all the values have been loaded into 2144 * SOC_INFO at this point, so fill the speed_config structure with 2145 * those values rather than reading from the config file */ 2146 if (SOC_WARM_BOOT(unit)) { 2147 rv = soc_esw_portctrl_speed_config_fill(unit, port, 2148 si->port_speed_max[port], 2149 si->port_num_lanes[port], 2150 si->port_fec_type[port], 2151 si->port_link_training[port], 2152 si->port_phy_lane_config[port], 2153 &speed_config_temp); 2154 } else { 2155 rv = soc_esw_portctrl_speed_config_fill(unit, port, 2156 -1, 2157 -1, 2158 -1, 2159 -1, 2160 -1, 2161 &speed_config_temp); 2162 } 2163 if (SOC_FAILURE(rv)) { 2164 goto vco_cleanup; 2165 } 2166 2167 /* look through our list of speeds for a free spot. Add the port's speed 2168 * and starting lane to the list */ 2169 for (j = 0; j < num_ports; j++) { 2170 2171 /* Empty entry if speed is 0 */ 2172 if (speed_config_list[j].speed == 0) { 2173 sal_memcpy(&speed_config_list[j], &speed_config_temp, 2174 sizeof(portmod_speed_config_t)); 2175 starting_lane_list[j] = i; 2176 num_speeds++; 2177 2178 /* Speed added to empty slot. Continue to next port */ 2179 break; 2180 } 2181 } 2182 2183 /* The above for loop will always break out with the port's current 2184 * settings. It will either break out when it has found a duplicate, 2185 * or if it has added a new entry to speed_config_list. So set 2186 * that info into SOC_INFO 2187 */ 2188 si->port_fec_type[port] = speed_config_list[j].fec; 2189 si->port_link_training[port] = speed_config_list[j].link_training; 2190 si->port_phy_lane_config[port] = speed_config_list[j].lane_config; 2191 } 2192 2193 /* Set the structure being passed to portmod, which will return 2194 * with the tvco and ovco */ 2195 /* coverity[leaked_storage] */ 2196 rv = portmod_pm_vco_setting_t_init(unit, &vco_setting); 2197 if (SOC_FAILURE(rv)) { 2198 goto vco_cleanup; 2199 } 2200 2201 vco_setting.speed_config_list = speed_config_list; 2202 vco_setting.speed_for_pcs_bypass_port = speed_for_pcs_bypass_port; 2203 vco_setting.port_starting_lane_list = starting_lane_list; 2204 vco_setting.num_speeds = num_speeds; 2205 2206 rv = portmod_pm_vcos_get(unit, pm_type, flags, &vco_setting); 2207 2208 /* Update the VCOs for this port macro */ 2209 si->pm_vco_info[pm_id].tvco = vco_setting.tvco; 2210 si->pm_vco_info[pm_id].ovco = vco_setting.ovco; 2211 2212 vco_cleanup: 2213 if (speed_config_list != NULL) { 2214 sal_free(speed_config_list); 2215 } 2216 if (speed_for_pcs_bypass_port != NULL) { 2217 sal_free(speed_for_pcs_bypass_port); 2218 } 2219 if (starting_lane_list != NULL) { 2220 sal_free(starting_lane_list); 2221 } 2222 2223 return rv; 2224 } 2225 2226 /* 2227 * Function: 2228 * _soc_esw_portctrl_pm_flex_fill_speed_config_list 2229 * Purpose: 2230 * This function fills speed_config_list with speeds in the port 2231 * macro. Each speed corresponds to a port. 2232 * Parameters: 2233 * unit - (IN) Unit number. 2234 * lanes_per_pm - (IN) Number of lanes in the PM 2235 * phy_ports_in - (IN) Array of phy ports in PM 2236 * port_iter - (IN) Index for phy_ports_in 2237 * starting_lane_list - (IN/OUT) The list containing starting lane for port 2238 * speed_config_list - (IN/OUT) The speed config list to fill 2239 * speeds - (OUT) count of the speeds. This MUST 2240 * be cleared in the calling function 2241 * 2242 * Returns: SOC_E_X 2243 */ 2244 STATIC int 2245 _soc_esw_portctrl_pm_flex_fill_speed_config_list(int unit, 2246 int lanes_per_pm, 2247 soc_port_resource_t **phy_ports_in, 2248 int port_iter, 2249 int *starting_lane_list, 2250 portmod_speed_config_t *speed_config_list, 2251 int *speeds) 2252 { 2253 int i; 2254 int count = 0; 2255 int rv = SOC_E_NONE; 2256 2257 for (i = 0; i < lanes_per_pm; i++) { 2258 /* Empty entry if speed is 0 */ 2259 if (speed_config_list[i].speed == 0) { 2260 /* Since lane config can equal -1 to mean auto, we don't 2261 * want the following function to misinterpret that as an 2262 * instruction to read the config file value for lane config. 2263 * So, if lane_config == -1, set it to -2 to tell this function 2264 * that the value needs to be auto 2265 */ 2266 if (phy_ports_in[port_iter]->phy_lane_config == -1) { 2267 phy_ports_in[port_iter]->phy_lane_config = -2; 2268 } 2269 rv = soc_esw_portctrl_speed_config_fill(unit, 2270 phy_ports_in[port_iter]->logical_port, 2271 phy_ports_in[port_iter]->speed, 2272 phy_ports_in[port_iter]->num_lanes, 2273 phy_ports_in[port_iter]->fec_type, 2274 phy_ports_in[port_iter]->link_training, 2275 phy_ports_in[port_iter]->phy_lane_config, 2276 &speed_config_list[i]); 2277 /* Set the starting lane equal to the port iterator that was passed 2278 * in mod lanes per pm. This is they physical lane for the pm */ 2279 starting_lane_list[i] = (port_iter - 1) % lanes_per_pm; 2280 2281 if (SOC_FAILURE(rv)) { 2282 return rv; 2283 } 2284 count++; 2285 break; 2286 } 2287 } 2288 /* Add count to the total */ 2289 *speeds += count; 2290 return rv; 2291 } 2292 2293 2294 /* 2295 * Function: 2296 * _soc_esw_portctrl_pm_flex_vco_validation 2297 * Purpose: 2298 * This function validates that a SINGLE port macro's flex configuration 2299 * is valid for the flexport scenario requested. 2300 * 2301 * It gathers the port and speed info requested and compares it with the 2302 * existing configuration (if there are ports that are persisting through 2303 * the flex), and validates that info. 2304 * 2305 * If everything is ok, it stores the port macro VCO information so that 2306 * it doesn't have to be recalculated again later. This VCO information 2307 * is then written to SOC_INFO at reconfiguration time. 2308 * 2309 * Parameters: 2310 * unit - (IN) Unit number. 2311 * port_schedule_state - (IN) Contains information for current PM state 2312 * phy_port - (IN) The physical port being flexed, which is 2313 * used to determine the PM affected 2314 * lanes_per_pm - (IN) The number of lanes in the port macro 2315 * phy_ports_in - (IN) An array of pointers to the soc_port_resource_t 2316 * of the physical ports being flexed. 2317 * Non-flexing port indexes will be NULL 2318 * phy_deleted_ports - (IN) an array of ports that will be deleted 2319 * in the flexport operation. Indexed by phy port 2320 * 2321 * Note: 2322 * phy_ports_in is essentially a hash where the key is physical ports. If 2323 * a port is flexing, the pointer will point to the flex operation. If the 2324 * entry is NULL, it means that port is not flexing to a new port. 2325 * 2326 * Returns: SOC_E_X 2327 */ 2328 2329 STATIC int 2330 _soc_esw_portctrl_pm_flex_vco_validation(int unit, 2331 soc_port_schedule_state_t *port_schedule_state, 2332 int phy_port, 2333 int lanes_per_pm, 2334 soc_port_resource_t **phy_ports_in, 2335 const uint8 *phy_deleted_ports) 2336 { 2337 #if defined(PORTMOD_SUPPORT) && defined(PORTMOD_PM8X50_SUPPORT) 2338 int port_iter; 2339 int pm_id, portmod_pm_id; 2340 int count; 2341 int base_phy_port; 2342 int rv; 2343 int logical_port; 2344 int pll_switch_flag; 2345 int *starting_lane_list = NULL; 2346 int *speed_for_pcs_bypass_port = NULL; 2347 soc_pmvco_info_t pm_vco_info; 2348 portmod_pm_vco_setting_t pm_vco_setting; 2349 portmod_pbmp_t flexing_ports; 2350 portmod_speed_config_t *speed_config_list = NULL; 2351 soc_port_map_type_t *in_port_map = &(port_schedule_state->in_port_map); 2352 2353 /* 2354 * Allocate space for flag that indicates if the 2355 * speed is for PCS bypass port. 2356 */ 2357 speed_for_pcs_bypass_port = sal_alloc(sizeof(int) * lanes_per_pm, 2358 "speed_for_pcs_bypass_port"); 2359 if (speed_for_pcs_bypass_port == NULL) { 2360 return SOC_E_MEMORY; 2361 } 2362 speed_config_list = sal_alloc(lanes_per_pm * sizeof(portmod_speed_config_t), 2363 "speed_config_list array"); 2364 if (speed_config_list == NULL) { 2365 rv = SOC_E_MEMORY; 2366 goto cleanup; 2367 } 2368 starting_lane_list = sal_alloc(sizeof(int) * lanes_per_pm, 2369 "starting_lane_list"); 2370 if (starting_lane_list == NULL) { 2371 rv = SOC_E_MEMORY; 2372 goto cleanup; 2373 } 2374 2375 /* Iterate through the affected ports in the PM. Verify 2376 * that the maximum number of VCOs isn't exceeded 2377 */ 2378 pm_id = (phy_port - 1) / lanes_per_pm; 2379 base_phy_port = (pm_id * lanes_per_pm) + 1; 2380 2381 sal_memset(speed_for_pcs_bypass_port, 0, sizeof(int) * lanes_per_pm); 2382 sal_memset(speed_config_list, 0, lanes_per_pm * sizeof(portmod_speed_config_t)); 2383 sal_memset(starting_lane_list, 0, sizeof(int) * lanes_per_pm); 2384 sal_memset(&pm_vco_setting, 0, sizeof(pm_vco_setting)); 2385 count = 0; 2386 PORTMOD_PBMP_CLEAR(flexing_ports); 2387 pll_switch_flag = PORTMOD_PM_SPEED_VALIDATE_F_TWO_PLL_SWITCH_ALLOWED; 2388 2389 for (port_iter = base_phy_port; port_iter < (base_phy_port + lanes_per_pm); 2390 port_iter++) { 2391 2392 if (phy_ports_in[port_iter] == NULL) { 2393 /* Not creating a new port */ 2394 2395 /* Skip if the port is being deleted */ 2396 if (phy_deleted_ports[port_iter] != 0) { 2397 continue; 2398 } 2399 2400 logical_port = in_port_map->port_p2l_mapping[port_iter]; 2401 2402 /* Port might not be mapped. Skip if it isn't mapped */ 2403 if (SOC_PBMP_PORT_VALID(logical_port)) { 2404 2405 /* Since not all ports on this PM are changing, only allow 2406 * one PLL switch 2407 */ 2408 pll_switch_flag = PORTMOD_PM_SPEED_VALIDATE_F_ONE_PLL_SWITCH_ALLOWED; 2409 } 2410 } else { 2411 /* Creating a new port, fill the config list */ 2412 rv = _soc_esw_portctrl_pm_flex_fill_speed_config_list( 2413 unit, 2414 lanes_per_pm, 2415 phy_ports_in, 2416 port_iter, 2417 starting_lane_list, 2418 speed_config_list, 2419 &count); 2420 2421 if (SOC_FAILURE(rv)) { 2422 goto cleanup; 2423 } 2424 } 2425 } 2426 2427 pm_vco_setting.speed_for_pcs_bypass_port = speed_for_pcs_bypass_port; 2428 pm_vco_setting.speed_config_list = speed_config_list; 2429 pm_vco_setting.port_starting_lane_list = starting_lane_list; 2430 pm_vco_setting.num_speeds = count; 2431 2432 /* Fill in the flexing ports port bitmap with all ports being deleted. 2433 * If a port is changing, it has to have been deleted 2434 */ 2435 for (port_iter = 1; port_iter < SOC_MAX_NUM_PORTS; port_iter++) { 2436 /* Check if the physical port is being deleted */ 2437 if (phy_deleted_ports[port_iter]) { 2438 /* Only add ports on the PM in question */ 2439 if (((port_iter - 1) / lanes_per_pm) == pm_id) { 2440 logical_port = in_port_map->port_p2l_mapping[port_iter]; 2441 PORTMOD_PBMP_PORT_ADD(flexing_ports, logical_port); 2442 } 2443 } 2444 } 2445 2446 2447 /* Portmod's indexing of the port macros differs from SDK's */ 2448 portmod_phy_pm_id_get(unit, phy_port, &portmod_pm_id); 2449 2450 rv = portmod_pm_speed_config_validate(unit, portmod_pm_id, &flexing_ports, 2451 pll_switch_flag, &pm_vco_setting); 2452 2453 if (SOC_FAILURE(rv)) { 2454 LOG_ERROR(BSL_LS_SOC_PORT, 2455 (BSL_META_U(unit, 2456 " VCO Validation " 2457 "Failed for Port Macro: %d\n" 2458 "Current VCOS: %d %d\n" 2459 "pll_switch_flag: %d\n"), 2460 pm_id, 2461 SOC_INFO(unit).pm_vco_info[pm_id].tvco, 2462 SOC_INFO(unit).pm_vco_info[pm_id].ovco, 2463 pll_switch_flag 2464 )); 2465 goto cleanup; 2466 } 2467 2468 2469 /* Save this information so that it doesn't have to be validated later */ 2470 pm_vco_info.tvco = pm_vco_setting.tvco; 2471 pm_vco_info.ovco = pm_vco_setting.ovco; 2472 /* Set is_tvco_new and is_ovco_new to 1, 2473 * indicating the vco in pm_vco_info is updated. */ 2474 pm_vco_info.is_tvco_new = 1; 2475 pm_vco_info.is_ovco_new = 1; 2476 2477 rv = soc_esw_portctrl_pm_vco_store(unit, pm_id, &pm_vco_info); 2478 2479 cleanup: 2480 if (speed_for_pcs_bypass_port != NULL) { 2481 sal_free(speed_for_pcs_bypass_port); 2482 speed_for_pcs_bypass_port = NULL; 2483 } 2484 if (speed_config_list != NULL) { 2485 sal_free(speed_config_list); 2486 speed_config_list = NULL; 2487 } 2488 if (starting_lane_list != NULL) { 2489 sal_free(starting_lane_list); 2490 starting_lane_list = NULL; 2491 } 2492 2493 return rv; 2494 #else 2495 return SOC_E_UNAVAIL; 2496 #endif /* defined(PORTMOD_SUPPORT && defined(PORTMOD_PM8X50_SUPPORT) */ 2497 } 2498 2499 2500 /* 2501 * Function: 2502 * soc_esw_portctrl_pm_vco_store 2503 * Purpose: 2504 * Calls a function vector, if it exists, to store PM VCO info so that 2505 * it won't have to be recalculated later 2506 * 2507 * Parameters: 2508 * unit - (IN) Unit number. 2509 * index - (IN) Port Macro index 2510 * pm_vco_info - (IN) VCO info want to store 2511 * 2512 * Note: 2513 * Does not directly affect SOC_INFO data 2514 * 2515 * Returns: SOC_E_X 2516 */ 2517 int 2518 soc_esw_portctrl_pm_vco_store(int unit, int index, const void *pm_vco_info) 2519 { 2520 int rv; 2521 2522 if ((SOC_PORTCTRL_FUNCTIONS(unit)) && 2523 (SOC_PORTCTRL_FUNCTIONS(unit)->soc_portctrl_pm_vco_store)) { 2524 rv = SOC_PORTCTRL_FUNCTIONS(unit)->soc_portctrl_pm_vco_store( 2525 unit, index, pm_vco_info); 2526 } else { 2527 rv = SOC_E_UNAVAIL; 2528 } 2529 2530 return rv; 2531 } 2532 2533 #endif /* PORTMOD_SUPPORT */ 2534 2535 /* 2536 * Function: 2537 * soc_esw_portctrl_pm_vco_reconfigure 2538 * Purpose: 2539 * Called to Reconfigure the VCOs in Port Macros affected during a flex 2540 * operation. This is called AFTER SOC_INFO has been updated with the new 2541 * VCO information. 2542 * Parameters: 2543 * unit - (IN) Unit number. 2544 * 2545 * Note: 2546 * 2547 * Returns: SOC_E_X 2548 */ 2549 int 2550 soc_esw_portctrl_pm_vco_reconfigure(int unit) 2551 { 2552 int rv; 2553 2554 if ((SOC_PORTCTRL_FUNCTIONS(unit)) && 2555 (SOC_PORTCTRL_FUNCTIONS(unit)->soc_portctrl_pm_vco_reconfigure)) { 2556 rv = SOC_PORTCTRL_FUNCTIONS(unit)->soc_portctrl_pm_vco_reconfigure( 2557 unit); 2558 } else { 2559 rv = SOC_E_UNAVAIL; 2560 } 2561 2562 return rv; 2563 } 2564 2565 /* 2566 * Function: 2567 * soc_esw_portctrl_pm_vco_fetch 2568 * Purpose: 2569 * Called to fetch the VCO information saved from a flex operation 2570 * calculation for use in setting SOC_INFO 2571 * Parameters: 2572 * unit - (IN) Unit number. 2573 * 2574 * Note: 2575 * Does not directly affect SOC_INFO data 2576 * 2577 * Returns: SOC_E_X 2578 */ 2579 int 2580 soc_esw_portctrl_pm_vco_fetch(int unit, int index, void *pm_vco_info) 2581 { 2582 #if defined(PORTMOD_SUPPORT) && defined(PORTMOD_PM8X50_SUPPORT) 2583 2584 int rv; 2585 2586 if ((SOC_PORTCTRL_FUNCTIONS(unit)) && 2587 (SOC_PORTCTRL_FUNCTIONS(unit)->soc_portctrl_pm_vco_fetch)) { 2588 rv = SOC_PORTCTRL_FUNCTIONS(unit)->soc_portctrl_pm_vco_fetch( 2589 unit, index, pm_vco_info); 2590 } else { 2591 rv = SOC_E_UNAVAIL; 2592 } 2593 2594 return rv; 2595 #else 2596 return SOC_E_UNAVAIL; 2597 #endif /* defined(PORTMOD_SUPPORT && defined(PORTMOD_PM8X50_SUPPORT) */ 2598 } 2599 2600 2601 /* 2602 * Function: 2603 * soc_esw_portctrl_flex_vco_validation 2604 * Purpose: 2605 * Called to validate the speed and vco configuration for all port macros 2606 * in the device. This function will examine the flexport operation 2607 * requested by the user, and will compare it with existing settings 2608 * in the device. It will then make sure that those configurations are 2609 * valid. 2610 * 2611 * Parameters: 2612 * unit - (IN) Unit number. 2613 * port_schedule_state - (IN) The flex information 2614 * Note: 2615 * 2616 * Returns: SOC_E_X 2617 */ 2618 int 2619 soc_esw_portctrl_flex_vco_validation(int unit, 2620 soc_port_schedule_state_t *port_schedule_state) 2621 { 2622 #if defined(PORTMOD_SUPPORT) && defined(PORTMOD_PM8X50_SUPPORT) 2623 2624 int i; 2625 int num_ports; 2626 int max_num_ports; 2627 int pm_id; 2628 int lanes_per_pm; 2629 portmod_dispatch_type_t pm_type; 2630 portmod_pm_capability_t pm_cap; 2631 /* Create a SOC_MAX_NUM_PORTS port array so that we can keep track of physical ports. 2632 * soc_pbmp_t only goes up to 256 bits, so it's not big enough */ 2633 uint8 phy_deleted_ports[SOC_MAX_NUM_PORTS]; 2634 int rv = SOC_E_NONE; 2635 soc_info_t *si = &SOC_INFO(unit); 2636 soc_port_resource_t *resource = port_schedule_state->resource; 2637 /* array of pointers indexed by physical ports seen in soc_port_resource_t 2638 * array the user sent 2639 * NULL = physical port was unseen 2640 * != NULL = pointer to the soc_port_resource_t 2641 */ 2642 soc_port_resource_t **phy_ports_in = NULL; 2643 2644 /* Physical Ports for front panel are index offset by 1 2645 * (start at physical port 1). Physical port 0 is CPU port. 2646 * So if Physical ports 1 - 256 are usable as front panel ports, 2647 * we want to be able to access index 256, so allocate 257 slots (0-256) */ 2648 max_num_ports = (SOC_MAX_NUM_PORTS + 1); 2649 2650 phy_ports_in = sal_alloc(max_num_ports * sizeof(soc_port_resource_t *), 2651 "Array of soc_port_resource_t *"); 2652 if (phy_ports_in == NULL) { 2653 return SOC_E_MEMORY; 2654 } 2655 2656 sal_memset(phy_ports_in, 0, max_num_ports * sizeof(soc_port_resource_t *)); 2657 2658 /* Keep track of the deleted ports */ 2659 sal_memset(phy_deleted_ports, 0, sizeof(phy_deleted_ports)); 2660 2661 num_ports = port_schedule_state->nport; 2662 2663 /* Mark the incoming physical ports in the phy_ports_in array. Indexes 2664 * that are NULL means that those ports are NOT flexing. 2665 */ 2666 for (i = 0; i < num_ports; i++) { 2667 /* skip ports being deleted */ 2668 if (resource[i].physical_port == -1) { 2669 /* mark the port as being deleted by marking it in the array 2670 */ 2671 phy_deleted_ports[si->port_l2p_mapping[resource[i].logical_port]] 2672 = 1; 2673 continue; 2674 } 2675 phy_ports_in[resource[i].physical_port] = &resource[i]; 2676 } 2677 2678 /* Validate for the post flex configuration that each PM doesn't exceed its 2679 * maximum number of VCOs 2680 */ 2681 for (i = 1; i < max_num_ports; i++) { 2682 /* Skip physical ports not seen */ 2683 if (phy_ports_in[i] == NULL) { 2684 continue; 2685 } 2686 #ifdef BCM_TOMAHAWK3_SUPPORT 2687 /* Tomahawk 3's Management Port Macro requires a spacing between 2688 * the lanes, so even though the two management ports' physical 2689 * ports are 257 and 258, the lane needs to be the next one, 2690 * so logical port 118 being mapped to physical port 258 needs 2691 * to pass 259 to portmod because portmod only recognizes lane 2692 * 0 (physical port 257) and lane 2 (physial port 259). 2693 */ 2694 if (SOC_IS_TOMAHAWK3(unit) && (i == 258)) { 2695 i = 259; 2696 } 2697 #endif 2698 2699 rv = (portmod_phy_pm_type_get(unit, i, &pm_type)); 2700 if (SOC_FAILURE(rv)) { 2701 goto cleanup; 2702 } 2703 switch (pm_type) { 2704 case portmodDispatchTypePm8x50: 2705 rv = (portmod_pm_capability_get(unit, pm_type, &pm_cap)); 2706 if (SOC_FAILURE(rv)) { 2707 goto cleanup; 2708 } 2709 2710 lanes_per_pm = pm_cap.pm_capability.pm8x50_cap.num_lanes; 2711 break; 2712 default: 2713 /* Skip Ports that are in PMs that are not PM8x50 */ 2714 continue; 2715 } 2716 /* This will verify that the post flex speeds on the port macro 2717 * are acceptable 2718 */ 2719 rv = _soc_esw_portctrl_pm_flex_vco_validation(unit, 2720 port_schedule_state, 2721 i, 2722 lanes_per_pm, 2723 phy_ports_in, 2724 phy_deleted_ports); 2725 if (SOC_FAILURE(rv)) { 2726 goto cleanup; 2727 } 2728 /* get the port macro id that this port belongs to */ 2729 pm_id = ((i - 1) / lanes_per_pm); 2730 2731 /* Go to the last port in the port macro. No sense in checking the 2732 * same port macro over and over again. 2733 * Example: We just finished PM0, which starts at physical port 1, so 2734 * go to PM1: ((0 + 1) * 8) = 8. The loop will increment to 9, which 2735 * is the start of the next PM 2736 */ 2737 i = ((pm_id + 1) * lanes_per_pm); 2738 } 2739 2740 2741 cleanup: 2742 if (phy_ports_in != NULL) { 2743 sal_free(phy_ports_in); 2744 } 2745 2746 return rv; 2747 #else 2748 return SOC_E_UNAVAIL; 2749 #endif /* defined(PORTMOD_SUPPORT && defined(PORTMOD_PM8X50_SUPPORT) */ 2750 } 2751 2752 2753 /* 2754 * Function: 2755 * soc_esw_portctrl_pm_vco_store_clear 2756 * Purpose: 2757 * Clears the calculated VCO information from a flexport operation 2758 * 2759 * Parameters: 2760 * unit - (IN) Unit number. 2761 * port_schedule_state - (IN) The flex information 2762 * Note: 2763 * Does not directly affect SOC_INFO data 2764 * 2765 * Returns: SOC_E_X 2766 */ 2767 int 2768 soc_esw_portctrl_pm_vco_store_clear(int unit) 2769 { 2770 #ifdef PORTMOD_SUPPORT 2771 int rv; 2772 2773 if ((SOC_PORTCTRL_FUNCTIONS(unit)) && 2774 (SOC_PORTCTRL_FUNCTIONS(unit)->soc_portctrl_pm_vco_store_clear)) { 2775 rv = SOC_PORTCTRL_FUNCTIONS(unit)->soc_portctrl_pm_vco_store_clear( 2776 unit); 2777 } else { 2778 rv = SOC_E_UNAVAIL; 2779 } 2780 2781 return rv; 2782 #else 2783 return SOC_E_NONE; 2784 #endif 2785 } 2786 2787 /* 2788 * Function: 2789 * soc_esw_portctrl_pm_ports_delete 2790 * Purpose: 2791 * Remove ports from the corresponding Port Macros. 2792 * Parameters: 2793 * unit - (IN) Unit number. 2794 * nport - (IN) Number of elements in array resource. 2795 * resource - (IN) Port Resource FlexPort configuration. 2796 * Returns: 2797 * SOC_E_XXX 2798 * Note: 2799 * - Assumes all data is Port Resource arrays has been validated. 2800 * - Must be called before SOC_INFO is updated. 2801 */ 2802 int 2803 soc_esw_portctrl_pm_ports_delete(int unit, 2804 int nport, 2805 soc_port_resource_t *resource) 2806 { 2807 #ifdef PORTMOD_SUPPORT 2808 int i; 2809 soc_port_resource_t *pr; 2810 2811 LOG_VERBOSE(BSL_LS_SOC_PORT, 2812 (BSL_META_U(unit, 2813 "SOC Port Macro Delete\n"))); 2814 2815 /* Check that PortCtrl has been initialized */ 2816 SOC_IF_ERROR_RETURN(soc_esw_portctrl_init_check(unit)); 2817 2818 for (i = 0, pr = &resource[0]; i < nport; i++, pr++) { 2819 LOG_VERBOSE(BSL_LS_SOC_PORT, 2820 (BSL_META_U(unit, 2821 " Port Macro delete " 2822 "logical_port=%d physical_port=%d\n"), 2823 pr->logical_port, pr->physical_port)); 2824 2825 /* portmod detach */ 2826 SOC_IF_ERROR_RETURN(soc_esw_portctrl_delete(unit, pr->logical_port)); 2827 } 2828 2829 return SOC_E_NONE; 2830 #else /* PORTMOD_SUPPORT */ 2831 return SOC_E_UNAVAIL; 2832 #endif /* PORTMOD_SUPPORT */ 2833 } 2834 2835 2836 /* 2837 * Function: 2838 * soc_esw_portctrl_pm_ports_add 2839 * Purpose: 2840 * Add ports and configure the relevant Port Macros for the given 2841 * the FlexPort configuration. 2842 * 2843 * This function reconfigures all the blocks inside 2844 * the PortMod library, this is xxPORT, MAC, and PHY. 2845 * Parameters: 2846 * unit - (IN) Unit number. 2847 * nport - (IN) Number of elements in array resource. 2848 * resource - (IN) Port Resource FlexPort configuration. 2849 * Returns: 2850 * SOC_E_XXX 2851 * Note: 2852 * - Assumes all data is Port Resource arrays has been validated. 2853 * - Must be called after SOC_INFO has been updated. 2854 * - Assumes ports has been already deleted. 2855 * - Caller must provide ALL ports (deleted and added), because 2856 * for it needs to 'add' NULL driver on cases where ports 2857 * become inactive. 2858 */ 2859 int 2860 soc_esw_portctrl_pm_ports_add(int unit, 2861 int nport, 2862 soc_port_resource_t *resource) 2863 { 2864 #ifdef PORTMOD_SUPPORT 2865 int i, lane=0, num_lanes, physical_port; 2866 soc_port_resource_t *pr; 2867 soc_info_t *si = &SOC_INFO(unit); 2868 portmod_pbmp_t phys; 2869 pbmp_t pbmp; 2870 #ifdef FW_BCAST_DOWNLOAD 2871 int bcast_flag, crc_en; 2872 #endif 2873 2874 LOG_VERBOSE(BSL_LS_SOC_PORT, 2875 (BSL_META_U(unit, 2876 "SOC Port Macro Add\n"))); 2877 2878 /* Check that PortCtrl has been initialized */ 2879 SOC_IF_ERROR_RETURN(soc_esw_portctrl_init_check(unit)); 2880 2881 PORTMOD_PBMP_CLEAR(phys); 2882 for (i = 0, pr = &resource[0]; i < nport; i++, pr++) { 2883 /* 2884 * Check if 'delete' port needs to be added (NULL driver). 2885 */ 2886 if ((pr->physical_port == -1) && 2887 !SOC_PBMP_MEMBER(si->all.disabled_bitmap, pr->logical_port)) { 2888 /* Port is deleted and is not inactive, nothing to add */ 2889 continue; 2890 } 2891 2892 num_lanes = SOC_INFO(unit).port_num_lanes[pr->logical_port]; 2893 if(num_lanes == 10) num_lanes=12; 2894 for (lane = 0; lane < num_lanes; lane++) { 2895 physical_port = SOC_INFO(unit).port_l2p_mapping[pr->logical_port]; 2896 #ifdef BCM_TRIDENT3_SUPPORT 2897 /*To support the 2nd MGMT port, convert its physical port to the dummy port number 131 on TD3.*/ 2898 if((SOC_IS_TRIDENT3(unit)) && (physical_port == 128) && (SOC_PBMP_MEMBER(SOC_INFO(unit).management_pbm, pr->logical_port))){ 2899 physical_port = 131; 2900 } 2901 #endif /* BCM_TRIDENT3_SUPPORT */ 2902 #ifdef BCM_TOMAHAWK3_SUPPORT 2903 /* Tomahawk 3's Management Port Macro requires a spacing between 2904 * the lanes, so even though the two management ports' physical 2905 * ports are 257 and 258, the lane needs to be the next one, 2906 * so logical port 118 being mapped to physical port 258 needs 2907 * to pass 259 to portmod because portmod only recognizes lane 2908 * 0 (physical port 257) and lane 2 (physial port 259). 2909 */ 2910 if (SOC_IS_TOMAHAWK3(unit) && pr->logical_port == 118) { 2911 physical_port = 259; 2912 } 2913 #endif 2914 SOC_IF_ERROR_RETURN( 2915 portmod_xphy_lane_detach(unit, physical_port + lane, 1)); 2916 SOC_PBMP_PORT_ADD(phys, physical_port + lane); 2917 } 2918 SOC_IF_ERROR_RETURN(soc_esw_portctrl_setup_ext_phy_add(unit, pr->logical_port, &phys)); 2919 } 2920 2921 /* Configure port in PortMod */ 2922 SOC_PBMP_CLEAR(pbmp); 2923 for (i = 0, pr = &resource[0]; i < nport; i++, pr++) { 2924 /* 2925 * In some cases, ports to be deleted become inactive. 2926 * In this case, the PortMod NULL driver needs to be installed 2927 * for the inactive port. 2928 * 2929 * The function soc_esw_portctrl_add() sets the right 2930 * information for the PortMod to install the correct 2931 * driver. 2932 */ 2933 2934 /* 2935 * Check if 'delete' port needs to be added (NULL driver). 2936 */ 2937 if ((pr->physical_port == -1) && 2938 !SOC_PBMP_MEMBER(si->all.disabled_bitmap, pr->logical_port)) { 2939 /* Port is deleted and is not inactive, nothing to add */ 2940 continue; 2941 } 2942 2943 /* Add port */ 2944 LOG_VERBOSE(BSL_LS_SOC_PORT, 2945 (BSL_META_U(unit, 2946 " Port Macro: Add " 2947 "logical_port=%d physical_port=%d\n"), 2948 pr->logical_port, pr->physical_port)); 2949 2950 SOC_IF_ERROR_RETURN(soc_esw_portctrl_add(unit, pr->logical_port, PORTMOD_PORT_ADD_F_INIT_CORE_PROBE, NULL)); 2951 SOC_IF_ERROR_RETURN(soc_esw_portctrl_add(unit, pr->logical_port, PORTMOD_PORT_ADD_F_INIT_PASS1, NULL)); 2952 SOC_PBMP_PORT_ADD(pbmp, pr->logical_port); 2953 } 2954 2955 #ifdef FW_BCAST_DOWNLOAD 2956 bcast_flag = soc_property_get(unit, spn_LOAD_FIRMWARE, 0); 2957 if (bcast_flag & 0xff0000) { 2958 crc_en = (bcast_flag >> 8) & 0xFF; 2959 SOC_IF_ERROR_RETURN(portmod_common_serdes_fw_bcst(unit, pbmp, crc_en)); 2960 } 2961 #endif 2962 2963 if (!(SOC_IS_TOMAHAWK2(unit) || SOC_IS_TOMAHAWK3(unit))) { 2964 SOC_IF_ERROR_RETURN(portmod_legacy_ext_phy_init(unit, pbmp)); 2965 2966 /* broadcast firmware download to all phymod based phys */ 2967 SOC_IF_ERROR_RETURN(portmod_common_ext_phy_fw_bcst(unit, &pbmp)); 2968 } 2969 2970 2971 for (i = 0, pr = &resource[0]; i < nport; i++, pr++) { 2972 2973 /* 2974 * Check if 'delete' port needs to be added (NULL driver). 2975 */ 2976 if ((pr->physical_port == -1) && 2977 !SOC_PBMP_MEMBER(si->all.disabled_bitmap, pr->logical_port)) { 2978 /* Port is deleted and is not inactive, nothing to add */ 2979 continue; 2980 } 2981 2982 /* Add port */ 2983 SOC_IF_ERROR_RETURN(soc_esw_portctrl_add(unit, pr->logical_port, PORTMOD_PORT_ADD_F_INIT_PASS2, NULL)); 2984 /* Leave port disabled */ 2985 SOC_IF_ERROR_RETURN(portmod_port_enable_set(unit, pr->logical_port, PORTMOD_PORT_ENABLE_PHY, 0)); 2986 } 2987 2988 return SOC_E_NONE; 2989 #else /* PORTMOD_SUPPORT */ 2990 return SOC_E_UNAVAIL; 2991 #endif /* PORTMOD_SUPPORT */ 2992 } 2993 2994 /* 2995 * Function: 2996 * soc_esw_portctrl_init 2997 * Purpose: 2998 * Initialize the Port Control component and 2999 * corresponding library (PortMod library). 3000 * 1. call soc_portctrl_pm_portmod_init 3001 * 2. set portctrl_init status to SOC_PORTCTRL_INITIALIZED. 3002 * 3003 * This is to be called by the SOC Port module initialization 3004 * function soc_misc_init(). 3005 * Parameters: 3006 * unit - (IN) Unit number. 3007 * Returns: 3008 * SOC_E_XXX 3009 */ 3010 int 3011 soc_esw_portctrl_init(int unit) 3012 { 3013 #ifdef PORTMOD_SUPPORT 3014 int rv; 3015 3016 /* Call Device specific PortMod library initialization */ 3017 rv = soc_portctrl_pm_portmod_init(unit); 3018 /* Successful */ 3019 if (SOC_SUCCESS(rv)) { 3020 portctrl_init[unit] = SOC_PORTCTRL_INITIALIZED; 3021 3022 if (SOC_WARM_BOOT(unit)) { 3023 rv = soc_portctrl_xport_type_verify(unit); 3024 } 3025 } 3026 return rv; 3027 #else /* PORTMOD_SUPPORT */ 3028 return SOC_E_UNAVAIL; 3029 #endif /* PORTMOD_SUPPORT */ 3030 } 3031 3032 /* 3033 * Function: 3034 * soc_esw_portctrl_deinit 3035 * Purpose: 3036 * Uninitialize the Port Control component and 3037 * corresponding library (PortMod library). 3038 * 1. call soc_portctrl_pm_portmod_deinit 3039 * 2. set portctrl_init status to SOC_PORTCTRL_NOT_INITIALIZED. 3040 * 3041 * This function must be called by the BCM Port module 3042 * deinit (or detach) function. 3043 * Parameters: 3044 * unit - (IN) Unit number. 3045 * Returns: 3046 * SOC_E_XXX 3047 */ 3048 int 3049 soc_esw_portctrl_deinit(int unit) 3050 { 3051 #ifdef PORTMOD_SUPPORT 3052 int rv; 3053 3054 if (SOC_PORTCTRL_NOT_INITIALIZED == portctrl_init[unit]) { 3055 return SOC_E_NONE; 3056 } 3057 3058 /* Call Device specific PortMod library uninitialization */ 3059 rv = soc_portctrl_pm_portmod_deinit(unit); 3060 portctrl_init[unit] = SOC_PORTCTRL_NOT_INITIALIZED; 3061 3062 return rv; 3063 #else /* PORTMOD_SUPPORT */ 3064 return SOC_E_UNAVAIL; 3065 #endif /* PORTMOD_SUPPORT */ 3066 } 3067 3068 3069 /* 3070 * Function: 3071 * soc_esw_portctrl_add 3072 * Purpose: 3073 * Add given logical port to PM (Port Macro). 3074 * Parameters: 3075 * unit - (IN) Unit number. 3076 * port - (IN) Port number. 3077 * Returns: 3078 * SOC_E_XXX 3079 * Notes: 3080 * Assume port is disabled. 3081 * Assume port has been removed from PM. 3082 * Assume caller has checked that PortCtrl was initialized. 3083 * SOC_INFO SW data structure has been updated. 3084 */ 3085 int 3086 soc_esw_portctrl_add(int unit, soc_port_t port, int init_flag, void *port_add_info) 3087 { 3088 #ifdef PORTMOD_SUPPORT 3089 portctrl_pport_t pport; 3090 portmod_port_add_info_t *add_info = NULL; 3091 portmod_port_add_info_t *local_add_info = NULL; 3092 int phy_port; 3093 int num_lanes; 3094 int speed; 3095 int lane, fwload_verify; 3096 int duplex; 3097 int ifg; 3098 soc_ipg_t *si; 3099 int rv = SOC_E_NONE; 3100 uint32 mtu_size; 3101 #ifdef PORTMOD_PM8X50_SUPPORT 3102 int is_init = 0; 3103 int pm_id, portmod_pm_id, phy_lane_config; 3104 portmod_pm_capability_t pm_cap; 3105 portmod_dispatch_type_t pm_type = portmodDispatchTypeCount; 3106 #endif 3107 3108 /* Convert port to PortMod port */ 3109 PORTCTRL_PORT_TO_PPORT(port, pport); 3110 3111 if (port_add_info != NULL) { 3112 add_info = (portmod_port_add_info_t*)port_add_info; 3113 } else { 3114 local_add_info = sal_alloc(sizeof(portmod_port_add_info_t), 3115 "portmod_port_add_info_t"); 3116 if (local_add_info == NULL) { 3117 LOG_ERROR(BSL_LS_SOC_PORT, 3118 (BSL_META_U(unit, "Mem Alloc Fail: portmod_port_add_info_t"))); 3119 rv = SOC_E_MEMORY; 3120 return rv; 3121 } 3122 3123 add_info = local_add_info; 3124 } 3125 3126 if (((port_add_info!=NULL) && 3127 (init_flag == PORTMOD_PORT_ADD_F_INIT_CORE_PROBE || !init_flag)) 3128 || (port_add_info==NULL)) { 3129 3130 rv = portmod_port_add_info_t_init(unit, add_info); 3131 if (PORTMOD_FAILURE(rv)) { 3132 if (local_add_info != NULL) { 3133 sal_free(local_add_info); 3134 } 3135 return rv; 3136 } 3137 3138 rv = soc_esw_portctrl_config_get(unit, port, 3139 &(add_info->interface_config), 3140 &(add_info->init_config), 3141 &(add_info->phy_op_mode)); 3142 if (SOC_FAILURE(rv)) { 3143 if (local_add_info != NULL) { 3144 sal_free(local_add_info); 3145 } 3146 return rv; 3147 } 3148 3149 add_info->phy_op_datapath= soc_property_port_get(unit, port, 3150 spn_PHY_ULL_DATAPATH, 3151 phymodDatapathNormal); 3152 3153 /* 3154 * Add port to PM 3155 */ 3156 phy_port = SOC_INFO(unit).port_l2p_mapping[port]; 3157 num_lanes = SOC_INFO(unit).port_num_lanes[port]; 3158 if (num_lanes == 10) { 3159 num_lanes = 12; 3160 } 3161 3162 #ifdef BCM_TRIDENT3_SUPPORT 3163 3164 if((SOC_IS_TRIDENT3(unit)) && (phy_port == 128)) { 3165 int pbm_count=0; 3166 SOC_PBMP_COUNT(SOC_INFO(unit).management_pbm, pbm_count); 3167 if (pbm_count == 2) { 3168 phy_port = 131; 3169 } 3170 } 3171 #endif /* BCM_TRIDENT3_SUPPORT */ 3172 3173 #ifdef BCM_TOMAHAWK3_SUPPORT 3174 /* Tomahawk 3's Management Port Macro requires a spacing between 3175 * the lanes, so even though the two management ports' physical 3176 * ports are 257 and 258, the lane needs to be the next one, 3177 * so logical port 118 being mapped to physical port 258 needs 3178 * to pass 259 to portmod because portmod only recognizes lane 3179 * 0 (physical port 257) and lane 2 (physial port 259). 3180 */ 3181 if (SOC_IS_TOMAHAWK3(unit) && (phy_port == 258)) { 3182 phy_port = 259; 3183 } 3184 #endif 3185 3186 /* 3187 * Set lane information 3188 * Assume lanes are arranged consecutively with respect to 3189 * the physical port number. 3190 */ 3191 for (lane = 0 ; lane < num_lanes; lane++) { 3192 PORTMOD_PBMP_PORT_ADD(add_info->phys, phy_port + lane); 3193 } 3194 } 3195 3196 add_info->flags = 0; 3197 3198 /* By default choose external fw load to speed up */ 3199 /* byte 0 defines fw load method, byte1 defines to verify the load */ 3200 fwload_verify = soc_property_get(unit, spn_LOAD_FIRMWARE, 2); 3201 3202 if ((fwload_verify >> 8) & 0xF) { 3203 PORTMOD_PORT_ADD_F_BYPASS_FW_CRC_CHECK_CLR(add_info); 3204 } else { 3205 PORTMOD_PORT_ADD_F_BYPASS_FW_CRC_CHECK_SET(add_info); 3206 } 3207 3208 if ((fwload_verify >> 12) & 0xF) { 3209 PORTMOD_PORT_ADD_F_FIRMWARE_LOAD_VERIFY_SET(add_info); 3210 } 3211 3212 #ifdef FW_BCAST_DOWNLOAD 3213 if (((fwload_verify >> 16) & 0xFF)) { 3214 PORTMOD_PORT_ADD_F_FIRMWARE_DOWNLOAD_BCAST_SET(add_info); 3215 } 3216 #endif 3217 3218 if (init_flag == PORTMOD_PORT_ADD_F_INIT_CORE_PROBE) { 3219 PORTMOD_PORT_ADD_F_INIT_CORE_PROBE_SET(add_info); 3220 } 3221 3222 if (init_flag == PORTMOD_PORT_ADD_F_INIT_PASS1) { 3223 PORTMOD_PORT_ADD_F_INIT_PASS1_SET(add_info); 3224 } 3225 3226 if (init_flag == PORTMOD_PORT_ADD_F_INIT_PASS2) { 3227 PORTMOD_PORT_ADD_F_INIT_PASS2_SET(add_info); 3228 } 3229 3230 if (SAL_BOOT_SIMULATION) { 3231 PORTMOD_PORT_ADD_F_FIRMWARE_LOAD_VERIFY_CLR(add_info); 3232 } 3233 3234 if (soc_feature(unit, soc_feature_clmac_16byte_interface_mode)) { 3235 PORTMOD_PORT_ADD_F_SYS_16B_INTF_MODE_SET(add_info); 3236 } 3237 #ifdef BCM_MONTEREY_SUPPORT 3238 if (SOC_IS_MONTEREY(unit)){ 3239 PORTMOD_PORT_ADD_F_TX_REPLACE_CRC_SET (add_info); 3240 } 3241 #endif 3242 #ifdef BCM_TOMAHAWK3_SUPPORT 3243 if (SOC_IS_TOMAHAWK3(unit)) { 3244 PORTMOD_PORT_ADD_F_TX_REPLACE_CRC_SET(add_info); 3245 } 3246 #endif 3247 #ifdef PORTMOD_PM8X50_SUPPORT 3248 phy_port = SOC_INFO(unit).port_l2p_mapping[port]; 3249 3250 #ifdef BCM_TOMAHAWK3_SUPPORT 3251 /* Tomahawk 3's Management Port Macro requires a spacing between 3252 * the lanes, so even though the two management ports' physical 3253 * ports are 257 and 258, the lane needs to be the next one, 3254 * so logical port 118 being mapped to physical port 258 needs 3255 * to pass 259 to portmod because portmod only recognizes lane 3256 * 0 (physical port 257) and lane 2 (physial port 259). 3257 */ 3258 if (SOC_IS_TOMAHAWK3(unit) && (phy_port == 258)) { 3259 phy_port = 259; 3260 } 3261 #endif 3262 3263 rv = portmod_phy_pm_type_get(unit, phy_port, &pm_type); 3264 3265 if (rv != SOC_E_UNAVAIL && rv < 0) { 3266 if (local_add_info != NULL) { 3267 sal_free(local_add_info); 3268 } 3269 return rv; 3270 } 3271 3272 /* for PM8x50 core init and adding ports to the PM are separated, 3273 * so we don't call portmod_port_add for both init and port add. 3274 * Just initialize the core here (if needed) and return. 3275 */ 3276 if (pm_type == portmodDispatchTypePm8x50) { 3277 /* Portmod's indexing of the port macros differs from SDK's */ 3278 portmod_phy_pm_id_get(unit, phy_port, &portmod_pm_id); 3279 3280 /* Check if the core is initialized */ 3281 rv = portmod_pm_is_initialized(unit, portmod_pm_id, &is_init); 3282 if (rv != SOC_E_UNAVAIL && rv < 0) { 3283 if (local_add_info != NULL) { 3284 sal_free(local_add_info); 3285 } 3286 return rv; 3287 } 3288 3289 /* Get the PM capability so we can figure out the # of lanes 3290 * per PM */ 3291 rv = portmod_pm_capability_get(unit, pm_type, &pm_cap); 3292 if (rv != SOC_E_UNAVAIL && rv < 0) { 3293 if (local_add_info != NULL) { 3294 sal_free(local_add_info); 3295 } 3296 return rv; 3297 } 3298 3299 /* PM 0 = phy ports 1-8 3300 * PM 1 = phy ports 9-16 3301 * PM 2 = phy ports 17-24 3302 * etc. */ 3303 pm_id = (phy_port - 1) / pm_cap.pm_capability.pm8x50_cap.num_lanes; 3304 3305 /* Set the TVCO and OVCO of these ports corresponding to 3306 * the PM they're a member of */ 3307 add_info->tvco = SOC_INFO(unit).pm_vco_info[pm_id].tvco; 3308 add_info->ovco = SOC_INFO(unit).pm_vco_info[pm_id].ovco; 3309 3310 /* Since lane config can equal -1 to mean auto, we don't 3311 * want the following function to misinterpret that as an 3312 * instruction to read the config file value for lane config. 3313 * So, if lane_config == -1, set it to -2 to tell this function 3314 * that the value needs to be auto 3315 */ 3316 phy_lane_config = SOC_INFO(unit).port_phy_lane_config[port]; 3317 if (phy_lane_config == -1) { 3318 phy_lane_config = -2; 3319 } 3320 3321 if (SOC_INFO(unit).port_init_speed[port] != 0) { 3322 speed = SOC_INFO(unit).port_init_speed[port]; 3323 } else { 3324 speed = SOC_INFO(unit).port_speed_max[port]; 3325 } 3326 3327 /* Set the speed_config information */ 3328 rv = soc_esw_portctrl_speed_config_fill(unit, 3329 port, 3330 speed, 3331 SOC_INFO(unit).port_num_lanes[port], 3332 SOC_INFO(unit).port_fec_type[port], 3333 SOC_INFO(unit).port_link_training[port], 3334 phy_lane_config, 3335 &(add_info->speed_config)); 3336 3337 3338 /* if the core is not initialized for this port, initialize it here */ 3339 if (!PORTMOD_CORE_INIT_FLAG_INITIALZIED_GET(is_init)) { 3340 3341 /* core init will be called for probe, pass 1, and pass 2 3342 * as instructed by the portmod team. 3343 */ 3344 rv = portmod_core_add(unit, portmod_pm_id, add_info); 3345 if (rv != SOC_E_UNAVAIL && rv < 0) { 3346 if (local_add_info != NULL) { 3347 sal_free(local_add_info); 3348 } 3349 return rv; 3350 } 3351 3352 } 3353 3354 /* Only allow the call to the below portmod_port_add on pass 2 3355 * because that means the core is init 3356 */ 3357 if (!((init_flag == PORTMOD_PORT_ADD_F_INIT_PASS2) || (init_flag == 0))) { 3358 if (local_add_info != NULL) { 3359 sal_free(local_add_info); 3360 } 3361 return rv; 3362 } 3363 3364 /* Clear the pass 2 flags because we want to call the port add 3365 * only once. 3366 */ 3367 add_info->flags &= ~PORTMOD_PORT_ADD_F_INIT_PASS2; 3368 } 3369 #endif 3370 3371 if (soc_feature(unit, soc_feature_clmac_16byte_interface_mode)) { 3372 PORTMOD_PORT_ADD_F_SYS_16B_INTF_MODE_SET(add_info); 3373 } 3374 3375 #if (defined BCM_HELIX5_SUPPORT) || (defined BCM_MAVERICK2_SUPPORT) 3376 if (SOC_IS_HELIX5(unit) || SOC_IS_MAVERICK2(unit)) { 3377 PORTMOD_PORT_ADD_F_IS_ENHANCED_PM4X25_GEN2_SET(add_info); 3378 } 3379 #endif 3380 3381 #if (defined BCM_MAVERICK2_SUPPORT) 3382 if (SOC_IS_MAVERICK2(unit)) { 3383 PORTMOD_PORT_ADD_F_DEFAULT_OSR2P5_SET(add_info); 3384 } 3385 #endif 3386 rv = portmod_port_add(unit, pport, add_info); 3387 if (PORTMOD_FAILURE(rv)) { 3388 if (local_add_info != NULL) { 3389 sal_free(local_add_info); 3390 } 3391 return rv; 3392 } 3393 3394 if ((init_flag == PORTMOD_PORT_ADD_F_INIT_PASS2) || (!init_flag)){ 3395 rv = soc_esw_portctrl_duplex_get(unit, port, &duplex); 3396 if (PORTMOD_FAILURE(rv)) { 3397 if (local_add_info != NULL) { 3398 sal_free(local_add_info); 3399 } 3400 return rv; 3401 } 3402 3403 si = &SOC_PERSIST(unit)->ipg[port]; 3404 if (IS_HG_PORT(unit, port)) { 3405 si->fd_hg = ifg = SOC_AVERAGE_IPG_HG; 3406 } else { 3407 si->fd_xe = ifg = SOC_AVERAGE_IPG_IEEE; 3408 } 3409 3410 #ifdef PORTMOD_PM8X50_SUPPORT 3411 if (pm_type == portmodDispatchTypePm8x50) { 3412 speed = add_info->speed_config.speed; 3413 } else 3414 #endif 3415 { 3416 speed = add_info->interface_config.speed; 3417 } 3418 3419 if (IS_CPRI_PORT(unit, port)) { 3420 return SOC_E_NONE; 3421 } 3422 rv = soc_esw_portctrl_ifg_set(unit, port, speed, duplex, ifg); 3423 3424 if (PORTMOD_FAILURE(rv)) { 3425 if (local_add_info != NULL) { 3426 sal_free(local_add_info); 3427 } 3428 return rv; 3429 } 3430 3431 mtu_size = SOC_INFO(unit).max_mtu; 3432 if (IS_XE_PORT(unit, port) || IS_GE_PORT(unit, port) 3433 || IS_CE_PORT(unit, port) 3434 || IS_CDE_PORT(unit, port) 3435 || (IS_C_PORT(unit, port) && IS_E_PORT(unit,port))) { 3436 /* For VLAN tagged packets */ 3437 mtu_size -= 4; 3438 } 3439 3440 rv = soc_esw_portctrl_frame_max_set(unit, pport, mtu_size); 3441 if (PORTMOD_FAILURE(rv)) { 3442 if (local_add_info != NULL) { 3443 sal_free(local_add_info); 3444 } 3445 return rv; 3446 } 3447 3448 #ifdef BCM_TRIDENT3_SUPPORT 3449 if (SOC_IS_TRIDENT3(unit)) { 3450 soc_info_t *si = &SOC_INFO(unit); 3451 if (((add_info->interface_config.speed == 27000) || 3452 (add_info->interface_config.speed == 53000))&& 3453 (!(si->oversub_mode))) { 3454 #if 1 3455 LOG_ERROR(BSL_LS_BCM_COMMON, 3456 (BSL_META_U(unit, 3457 "27G/53G speeed in Line rate config is not supported.\n"))); 3458 if (local_add_info != NULL) { 3459 sal_free(local_add_info); 3460 } 3461 return SOC_E_CONFIG; 3462 #endif 3463 } 3464 } 3465 #endif /* BCM_TRIDENT3_SUPPORT */ 3466 3467 rv = soc_esw_portctrl_port_fc_config_init(unit, pport); 3468 if (PORTMOD_FAILURE(rv)) { 3469 if (local_add_info != NULL) { 3470 sal_free(local_add_info); 3471 } 3472 return rv; 3473 } 3474 } 3475 3476 if (local_add_info != NULL) { 3477 sal_free(local_add_info); 3478 } 3479 3480 return SOC_E_NONE; 3481 3482 #else /* PORTMOD_SUPPORT */ 3483 return SOC_E_UNAVAIL; 3484 #endif /* PORTMOD_SUPPORT */ 3485 } 3486 3487 3488 /* 3489 * Function: 3490 * soc_esw_portctrl_delete 3491 * Purpose: 3492 * Remove given logical port from PM (Port Macro). 3493 * Parameters: 3494 * unit - (IN) Unit number. 3495 * port - (IN) Port number. 3496 * Returns: 3497 * SOC_E_XXX 3498 * Notes: 3499 * Assume port is disabled. 3500 * Assume caller has checked that PortCtrl was initialized. 3501 * SOC_INFO SW data structure has been updated. 3502 */ 3503 int 3504 soc_esw_portctrl_delete(int unit, soc_port_t port) 3505 { 3506 #ifdef PORTMOD_SUPPORT 3507 portctrl_pport_t pport; 3508 int valid; 3509 3510 /* Convert port to PortMod port */ 3511 PORTCTRL_PORT_TO_PPORT(port, pport); 3512 3513 /* Remove port */ 3514 PORTMOD_IF_ERROR_RETURN(portmod_port_is_valid(unit, pport, &valid)); 3515 if (valid) { 3516 PORTMOD_IF_ERROR_RETURN(portmod_port_remove(unit, pport)); 3517 } 3518 3519 return SOC_E_NONE; 3520 3521 #else /* PORTMOD_SUPPORT */ 3522 return SOC_E_UNAVAIL; 3523 #endif /* PORTMOD_SUPPORT */ 3524 } 3525 3526 3527 /* 3528 * Function: 3529 * soc_esw_portctrl_pgw_reconfigure 3530 * Purpose: 3531 * This function is called during reconfiguration of PGW during 3532 * flexing operation. 3533 * Parameters: 3534 * unit - (IN) Unit number. 3535 * port - (IN) Logical Port number. 3536 * phy_port - (IN) Physical Port number. 3537 * Returns: 3538 * SOC_E_XXX 3539 * Notes: 3540 * Assumes port is disabled. 3541 * Assumes caller has checked that PortCtrl was initialized. 3542 * SOC_INFO SW data structure has been updated. 3543 */ 3544 int 3545 soc_esw_portctrl_pgw_reconfigure(int unit, soc_port_t port, 3546 int phy_port, 3547 soc_esw_portctrl_pgw_t *pgw_data) 3548 { 3549 #ifdef PORTMOD_SUPPORT 3550 portmod_port_mode_info_t info; 3551 3552 portmod_port_mode_info_t_init(unit, &info); 3553 3554 info.cur_mode = pgw_data->mode; 3555 info.lanes = pgw_data->lanes; 3556 info.port_index = pgw_data->port_index; 3557 3558 pgw_data->flags = PORTMOD_PORT_PGW_CONFIGURE; 3559 3560 /* Note this portmod API requires logical port */ 3561 PORTMOD_IF_ERROR_RETURN(portmod_port_pgw_reconfig(unit, port, &info, 3562 phy_port, pgw_data->flags)); 3563 3564 return SOC_E_NONE; 3565 #else /* PORTMOD_SUPPORT */ 3566 return SOC_E_UNAVAIL; 3567 #endif /* PORTMOD_SUPPORT */ 3568 } 3569 3570 /* 3571 * Function: 3572 * soc_esw_portctrl_duplex_get 3573 * Purpose: 3574 * Get the port duplex settings 3575 * Parameters: 3576 * unit - StrataSwitch Unit #. 3577 * port - StrataSwitch port #. 3578 * duplex - (OUT) Duplex setting, one of SOC_PORT_DUPLEX_xxx 3579 * Returns: 3580 * BCM_E_NONE 3581 * BCM_E_XXX 3582 */ 3583 int 3584 soc_esw_portctrl_duplex_get(int unit, soc_port_t port, int *duplex) 3585 { 3586 #ifdef PORTMOD_SUPPORT 3587 int rv = SOC_E_NONE; 3588 portctrl_pport_t pport; 3589 int port_duplex; 3590 int is_legacy_phy_present; 3591 int is_macsec_enabled; 3592 3593 SOC_IF_ERROR_RETURN(soc_esw_portctrl_init_check(unit)); 3594 3595 PORTCTRL_PORT_TO_PPORT(port, pport); 3596 3597 SOC_IF_ERROR_RETURN(portmod_port_is_legacy_ext_phy_present(unit, pport, &is_legacy_phy_present)); 3598 3599 is_macsec_enabled = soc_property_port_get(unit, pport, spn_MACSEC_ENABLE, 0); 3600 3601 if (is_legacy_phy_present && is_macsec_enabled) { 3602 rv = portmod_port_legacy_duplex_get(unit, pport, &port_duplex); 3603 } else { 3604 rv = portmod_port_duplex_get(unit, pport, &port_duplex); 3605 } 3606 3607 if (PORTMOD_SUCCESS(rv)) { 3608 *duplex = port_duplex ? SOC_PORT_DUPLEX_FULL : SOC_PORT_DUPLEX_HALF; 3609 } else { 3610 *duplex = SOC_PORT_DUPLEX_FULL; 3611 } 3612 3613 return rv; 3614 #else /* PORTMOD_SUPPORT */ 3615 return SOC_E_UNAVAIL; 3616 #endif /* PORTMOD_SUPPORT */ 3617 } 3618 3619 /* 3620 * Function: 3621 * soc_esw_portctrl_duplex_set 3622 * Purpose: 3623 * Set the port duplex 3624 * Parameters: 3625 * unit - StrataSwitch Unit #. 3626 * port - StrataSwitch port #. 3627 * duplex - Duplex setting, one of SOC_PORT_DUPLEX_xxx 3628 * Returns: 3629 * BCM_E_NONE 3630 * BCM_E_XXX 3631 */ 3632 int 3633 soc_esw_portctrl_duplex_set(int unit, soc_port_t port, int duplex) 3634 { 3635 #ifdef PORTMOD_SUPPORT 3636 int rv = SOC_E_NONE; 3637 portctrl_pport_t pport; 3638 int is_legacy_phy_present; 3639 int is_macsec_enabled; 3640 3641 SOC_IF_ERROR_RETURN(soc_esw_portctrl_init_check(unit)); 3642 3643 PORTCTRL_PORT_TO_PPORT(port, pport); 3644 3645 SOC_IF_ERROR_RETURN(portmod_port_is_legacy_ext_phy_present(unit, pport, &is_legacy_phy_present)); 3646 3647 is_macsec_enabled = soc_property_port_get(unit, pport, spn_MACSEC_ENABLE, 0); 3648 3649 if (is_legacy_phy_present && is_macsec_enabled) { 3650 rv = portmod_port_legacy_duplex_set(unit, pport, duplex); 3651 } else { 3652 rv = portmod_port_duplex_set(unit, pport, duplex); 3653 } 3654 3655 return rv; 3656 #else /* PORTMOD_SUPPORT */ 3657 return SOC_E_UNAVAIL; 3658 #endif /* PORTMOD_SUPPORT */ 3659 } 3660 3661 3662 /* 3663 * Function: 3664 * soc_esw_portctrl_port_fc_config_init 3665 * Purpose: 3666 * Configure default flow control configuration 3667 * in the port macro. Depending on the each chip's 3668 * support level, we will either have to program 3669 * PARALLEL_FC_EN to 1 or 0. Depending on this config 3670 * either the serial interface (mmu flow control) or 3671 * the parallel interface (for obm flow control) is used. 3672 * For devices where the flow control is to be used from 3673 * both the interfaces, we need to enable merge mode (and 3674 * not configure parallel_fc_en). 3675 * 3676 * Parameters: 3677 * unit - StrataSwitch Unit #. 3678 * port - StrataSwitch port #. 3679 * Returns: 3680 * BCM_E_NONE 3681 * BCM_E_XXX 3682 */ 3683 int 3684 soc_esw_portctrl_port_fc_config_init(int unit, soc_port_t port) 3685 { 3686 #ifdef PORTMOD_SUPPORT 3687 int rv = SOC_E_NONE; 3688 portctrl_pport_t pport; 3689 3690 /* 3691 * Note that MMU uses serial interface (legacy) and OBM uses parallel 3692 * interface for pause control. If pause from only OBM is required, then 3693 * we should enable parallel_fc mode. Disabling parallel fc mode enables 3694 * the legacy serial interface. When pause from both the interfaces are 3695 * desired, then merge_mode_en should be enabled. 3696 * 3697 * For Apache, FC signals from MMU and OBM must be honored for 3698 * proper flow control handling. 3699 */ 3700 if (soc_feature(unit, soc_feature_pm_fc_merge_mode) && !IS_QSGMII_PORT(unit, port)) { 3701 SOC_IF_ERROR_RETURN(soc_esw_portctrl_init_check(unit)); 3702 3703 PORTCTRL_PORT_TO_PPORT(port, pport); 3704 3705 rv = portmod_port_flow_control_set(unit, pport, 3706 1 /* merge_mode */, 3707 0 /* parallel_fc */); 3708 } 3709 3710 return rv; 3711 #else /* PORTMOD_SUPPORT */ 3712 return SOC_E_UNAVAIL; 3713 #endif /* PORTMOD_SUPPORT */ 3714 } 3715 3716 3717 int 3718 soc_esw_portctrl_frame_max_set(int unit, soc_port_t port, int size) 3719 { 3720 #ifdef PORTMOD_SUPPORT 3721 int rv = SOC_E_NONE; 3722 portctrl_pport_t pport; 3723 int max_size = SOC_INFO(unit).max_mtu; 3724 soc_reg_t reg; 3725 egr_mtu_entry_t mtu; 3726 uint32 rval; 3727 uint32 mtu_size; 3728 3729 SOC_IF_ERROR_RETURN(soc_esw_portctrl_init_check(unit)); 3730 3731 PORTCTRL_PORT_TO_PPORT(port, pport); 3732 3733 if (size < 0) { 3734 return SOC_E_PARAM; 3735 } 3736 3737 if (IS_XE_PORT(unit, port) || IS_GE_PORT(unit, port) 3738 || IS_CE_PORT(unit, port) 3739 || IS_CDE_PORT(unit, port) 3740 || (IS_C_PORT(unit, port) && IS_E_PORT(unit,port))) { 3741 /* For VLAN tagged packets */ 3742 size += 4; 3743 } 3744 3745 if (size > max_size) { 3746 return SOC_E_PARAM; 3747 } 3748 3749 rv = portmod_port_max_packet_size_set(unit, pport, size); 3750 3751 if (PORTMOD_SUCCESS(rv)) { 3752 soc_mem_t mem = EGR_MTUm; 3753 if (SOC_MEM_IS_VALID(unit, mem)) { 3754 if (soc_feature(unit, soc_feature_egr_all_profile)) { 3755 int field_cnt = 0; 3756 soc_field_t fields[2]; 3757 uint32 values[2]; 3758 3759 fields[field_cnt] = MTU_SIZEf; 3760 values[field_cnt++] = size; 3761 fields[field_cnt] = MTU_ENABLEf; 3762 values[field_cnt++] = 1; 3763 rv = bcm_esw_port_egr_lport_fields_set(unit, port, mem, 3764 field_cnt, fields, values); 3765 } else { 3766 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, port, &mtu); 3767 if (SOC_SUCCESS(rv)) { 3768 mtu_size = size; 3769 soc_mem_field32_set(unit, mem, &mtu, MTU_SIZEf, mtu_size); 3770 if (soc_mem_field_valid(unit, EGR_MTUm, MTU_ENABLEf)) { 3771 soc_mem_field32_set(unit, EGR_MTUm, &mtu, MTU_ENABLEf, 1); 3772 } 3773 rv = soc_mem_write(unit, mem, MEM_BLOCK_ANY, port, &mtu); 3774 } 3775 } 3776 } else { 3777 reg = SOC_REG_IS_VALID(unit, EGR_MTUr) ? EGR_MTUr : EGR_MTU_SIZEr; 3778 3779 rv = soc_reg32_get(unit, reg, port, 0, &rval); 3780 if (SOC_SUCCESS(rv)) { 3781 soc_reg_field_set(unit, reg, &rval, MTU_SIZEf, size); 3782 if (soc_reg_field_valid(unit, reg, MTU_ENABLEf)) { 3783 soc_reg_field_set(unit, reg, &rval, MTU_ENABLEf, 1); 3784 } 3785 rv = soc_reg32_set(unit, reg, port, 0, rval); 3786 } 3787 } 3788 } 3789 3790 return rv; 3791 3792 #else /* PORTMOD_SUPPORT */ 3793 return SOC_E_UNAVAIL; 3794 #endif /* PORTMOD_SUPPORT */ 3795 } 3796 3797 3798 int 3799 soc_esw_portctrl_frame_max_get(int unit, soc_port_t port, int *size) 3800 { 3801 #ifdef PORTMOD_SUPPORT 3802 int rv = SOC_E_NONE; 3803 portctrl_pport_t pport; 3804 3805 SOC_IF_ERROR_RETURN(soc_esw_portctrl_init_check(unit)); 3806 3807 PORTCTRL_PORT_TO_PPORT(port, pport); 3808 3809 rv = portmod_port_max_packet_size_get(unit, pport, size); 3810 3811 if (IS_XE_PORT(unit, port) || IS_GE_PORT(unit, port) 3812 || IS_CE_PORT(unit, port) 3813 || IS_CDE_PORT(unit, port) 3814 || (IS_C_PORT(unit, port) && IS_E_PORT(unit,port))) { 3815 /* For VLAN tagged packets */ 3816 *size -= 4; 3817 } 3818 3819 return rv; 3820 #else /* PORTMOD_SUPPORT */ 3821 return SOC_E_UNAVAIL; 3822 #endif /* PORTMOD_SUPPORT */ 3823 } 3824 3825 int 3826 soc_esw_portctrl_pause_set(int unit, soc_port_t port, int pause_tx, int pause_rx) 3827 { 3828 #ifdef PORTMOD_SUPPORT 3829 int rv; 3830 portctrl_pport_t pport; 3831 portmod_pause_control_t control; 3832 3833 SOC_IF_ERROR_RETURN(soc_esw_portctrl_init_check(unit)); 3834 3835 PORTCTRL_PORT_TO_PPORT(port, pport); 3836 3837 portmod_pause_control_t_init(unit, &control); 3838 3839 rv = portmod_port_pause_control_get(unit, pport, &control); 3840 if (PORTMOD_SUCCESS(rv)) { 3841 control.tx_enable = pause_tx ? TRUE : FALSE; 3842 control.rx_enable = pause_rx ? TRUE : FALSE; 3843 rv = portmod_port_pause_control_set(unit, pport, &control); 3844 } 3845 return rv; 3846 #else /* PORTMOD_SUPPORT */ 3847 return SOC_E_UNAVAIL; 3848 #endif /* PORTMOD_SUPPORT */ 3849 } 3850 3851 int 3852 soc_esw_portctrl_pause_get(int unit, soc_port_t port, int *pause_tx, int *pause_rx) 3853 { 3854 #ifdef PORTMOD_SUPPORT 3855 int rv; 3856 portctrl_pport_t pport; 3857 portmod_pause_control_t control; 3858 3859 SOC_IF_ERROR_RETURN(soc_esw_portctrl_init_check(unit)); 3860 3861 PORTCTRL_PORT_TO_PPORT(port, pport); 3862 3863 portmod_pause_control_t_init(unit, &control); 3864 3865 rv = portmod_port_pause_control_get(unit, pport, &control); 3866 if (PORTMOD_SUCCESS(rv)) { 3867 *pause_tx = control.tx_enable ? TRUE : FALSE; 3868 *pause_rx = control.rx_enable ? TRUE : FALSE; 3869 } 3870 return rv; 3871 #else /* PORTMOD_SUPPORT */ 3872 return SOC_E_UNAVAIL; 3873 #endif /* PORTMOD_SUPPORT */ 3874 } 3875 3876 /* 3877 * Function: 3878 * soc_esw_portctrl_ifg_set 3879 * Purpose: 3880 * Set Inter Frame Gap 3881 * Parameters: 3882 * unit - StrataSwitch unit number. 3883 * port - Port. 3884 * speed - Speed 3885 * duplex - Duplex Setting 3886 * ifg - InterFrame Gap 3887 * Returns: 3888 * BCM_E_NONE 3889 * BCM_E_INTERNAL - internal error. 3890 */ 3891 int 3892 soc_esw_portctrl_ifg_set(int unit, soc_port_t port, int speed, 3893 soc_port_duplex_t duplex, int ifg) 3894 { 3895 #ifdef PORTMOD_SUPPORT 3896 int rv = SOC_E_NONE; 3897 portctrl_pport_t pport; 3898 soc_ipg_t *si; 3899 int real_ifg = 0; 3900 int cur_speed; 3901 int cur_duplex; 3902 portmod_port_ability_t ability; 3903 uint32 pa_flag; 3904 #ifdef PORTMOD_PM8X50_SUPPORT 3905 portmod_dispatch_type_t pm_type = portmodDispatchTypeCount; 3906 int phy_port; 3907 #endif 3908 3909 SOC_IF_ERROR_RETURN(soc_esw_portctrl_init_check(unit)); 3910 3911 PORTCTRL_PORT_TO_PPORT(port, pport); 3912 3913 #ifdef PORTMOD_PM8X50_SUPPORT 3914 phy_port = SOC_INFO(unit).port_l2p_mapping[port]; 3915 if ((SOC_PORTCTRL_FUNCTIONS(unit)) && 3916 SOC_PORTCTRL_FUNCTIONS(unit)->soc_portctrl_pm_type_get) { 3917 rv = SOC_PORTCTRL_FUNCTIONS(unit)->soc_portctrl_pm_type_get( 3918 unit, phy_port, ((int *)&pm_type)); 3919 } 3920 3921 /* PM8x50 doesn't support ability local get */ 3922 if (pm_type != portmodDispatchTypePm8x50) 3923 #endif 3924 { 3925 pa_flag = SOC_PA_SPEED(speed); 3926 sal_memset(&ability, 0, sizeof(portmod_port_ability_t)); 3927 3928 rv = portmod_port_ability_local_get(unit, pport, PORTMOD_INIT_F_EXTERNAL_MOST_ONLY, &ability); 3929 SOC_IF_ERROR_RETURN(rv); 3930 3931 if (!(pa_flag & ability.speed_full_duplex)) { 3932 return SOC_E_PARAM; 3933 } 3934 } 3935 3936 SOC_IF_ERROR_RETURN(portmod_port_duplex_get(unit, pport, &cur_duplex)); 3937 SOC_IF_ERROR_RETURN(portmod_port_speed_get(unit, pport, &cur_speed)); 3938 3939 /* XLMAC_MODE supports only 4 speeds with 4 being max as LINK_10G_PLUS */ 3940 if ((speed > 10000) && (cur_speed == 10000)) { 3941 cur_speed = speed; 3942 } 3943 3944 if (cur_speed == speed && 3945 cur_duplex == (duplex == SOC_PORT_DUPLEX_FULL ? TRUE : FALSE)) { 3946 rv = portmod_port_tx_average_ipg_set (unit, pport, ifg); 3947 SOC_IF_ERROR_RETURN(rv); 3948 } 3949 3950 if (PORTMOD_SUCCESS(rv)) { 3951 SOC_IF_ERROR_RETURN(portmod_port_tx_average_ipg_get(unit, pport, &real_ifg)); 3952 si = &SOC_PERSIST(unit)->ipg[port]; 3953 if (IS_HG_PORT(unit, port)) { 3954 si->fd_hg = real_ifg ; 3955 } else { 3956 si->fd_xe = real_ifg ; 3957 } 3958 } 3959 3960 return rv; 3961 #else /* PORTMOD_SUPPORT */ 3962 return SOC_E_UNAVAIL; 3963 #endif /* PORTMOD_SUPPORT */ 3964 } 3965 3966 /* 3967 * Function: 3968 * soc_esw_portctrl_ifg_get 3969 * Purpose: 3970 * Get Inter Frame Gap 3971 * Parameters: 3972 * unit - StrataSwitch unit number. 3973 * port - Port. 3974 * speed - Speed 3975 * duplex - Duplex Setting 3976 * ifg - InterFrame Gap 3977 * Returns: 3978 * BCM_E_NONE 3979 * BCM_E_INTERNAL - internal error. 3980 */ 3981 int 3982 soc_esw_portctrl_ifg_get(int unit, soc_port_t port, int speed, 3983 soc_port_duplex_t duplex, int *ifg) 3984 { 3985 #ifdef PORTMOD_SUPPORT 3986 int rv = SOC_E_NONE; 3987 soc_ipg_t *si; 3988 uint32 pa_flag; 3989 portctrl_pport_t pport; 3990 portmod_port_ability_t ability; 3991 3992 SOC_IF_ERROR_RETURN(soc_esw_portctrl_init_check(unit)); 3993 3994 PORTCTRL_PORT_TO_PPORT(port, pport); 3995 3996 if (!SOC_IS_TOMAHAWK3(unit)) { 3997 pa_flag = SOC_PA_SPEED(speed); 3998 sal_memset(&ability, 0, sizeof(portmod_port_ability_t)); 3999 4000 rv = portmod_port_ability_local_get(unit, pport, PORTMOD_INIT_F_EXTERNAL_MOST_ONLY, &ability); 4001 SOC_IF_ERROR_RETURN(rv); 4002 4003 if (!(pa_flag & ability.speed_full_duplex)) { 4004 return SOC_E_PARAM; 4005 } 4006 } 4007 si = &SOC_PERSIST(unit)->ipg[port]; 4008 if (IS_HG_PORT(unit, port)) { 4009 *ifg = si->fd_hg; 4010 } else { 4011 *ifg = si->fd_xe; 4012 } 4013 4014 return rv; 4015 #else /* PORTMOD_SUPPORT */ 4016 return SOC_E_UNAVAIL; 4017 #endif /* PORTMOD_SUPPORT */ 4018 } 4019 4020 /* 4021 * Function: 4022 * soc_portctrl_led_chain_config 4023 * Purpose: 4024 * Set the port mode 4025 * Parameters: 4026 * unit - SOC Unit # 4027 * port - Port # 4028 * value - Intra-Port delay for each subports in PORT block 4029 * Returns: 4030 * SOC_E_XXX 4031 */ 4032 int 4033 soc_portctrl_led_chain_config(int unit, int port, int value) 4034 { 4035 #ifdef PORTMOD_SUPPORT 4036 return portmod_port_led_chain_config(unit, port, value); 4037 4038 #else /* PORTMOD_SUPPORT */ 4039 return SOC_E_UNAVAIL; 4040 #endif /* PORTMOD_SUPPORT */ 4041 } 4042 4043 /* 4044 * Function: 4045 * soc_portctrl_phy_name_get 4046 * Purpose: 4047 * Get the phy name of the given port 4048 * Parameters: 4049 * unit - SOC Unit #. 4050 * port - Port #. 4051 * phy_name - PHY name string. Note: The max length of PHY name is 32. 4052 * Returns: 4053 * SOC_E_XXX 4054 */ 4055 int 4056 soc_portctrl_phy_name_get(int unit, int port, char *phy_name) 4057 { 4058 #ifdef PORTMOD_SUPPORT 4059 phymod_core_access_t core_acc; 4060 phymod_core_info_t core_info; 4061 int nof_cores = 0; 4062 char *pname = NULL, namelen; 4063 portmod_port_diag_info_t diag_info; 4064 int phy = 0, core_num = 0, pcount = 0; 4065 int range_start = 0; 4066 int rv; 4067 4068 if (NULL == phy_name) { 4069 return SOC_E_PARAM; 4070 } 4071 sal_memset(&diag_info, 0, sizeof(portmod_port_diag_info_t)); 4072 sal_memset(phy_name, 0, sizeof(char)*SOC_PM_PHY_NAME_MAX_LEN); 4073 4074 portmod_port_core_access_get(unit, port, -1, 1, &core_acc, &nof_cores, NULL); 4075 if (nof_cores == 0) { 4076 LOG_VERBOSE(BSL_LS_SOC_PORT, 4077 (BSL_META_UP(unit, port, 4078 "ERROR: getting port%d information.\n"), 4079 port)); 4080 sal_snprintf(phy_name, SOC_PM_PHY_NAME_MAX_LEN, "%s", "<nophy>"); 4081 return SOC_E_NONE; 4082 } 4083 4084 /* 4085 * COVERITY 4086 * 4087 * It doesn't check return value. 4088 */ 4089 /* coverity[check_return] */ 4090 phymod_core_info_get(&core_acc, &core_info); 4091 rv = portmod_port_diag_info_get(unit, port, &diag_info); 4092 if (SOC_FAILURE(rv)) { 4093 return rv; 4094 } 4095 rv = portmod_port_core_num_get(unit, port, &core_num); 4096 if (SOC_FAILURE(rv)) { 4097 return rv; 4098 } 4099 4100 PORTMOD_PBMP_ITER(diag_info.phys, phy){ 4101 range_start = phy; 4102 break; 4103 } 4104 4105 PORTMOD_PBMP_COUNT(diag_info.phys, pcount); 4106 pname = phymod_core_version_t_mapping[core_info.core_version].key; 4107 namelen = strlen(pname); 4108 4109 sal_snprintf(phy_name, SOC_PM_PHY_NAME_MAX_LEN, "%s", pname); 4110 sal_snprintf(phy_name+namelen, SOC_PM_PHY_NAME_MAX_LEN-namelen, "/%02d/", core_num); 4111 4112 pname = phy_name+strlen(phy_name); 4113 if (pcount == 4) 4114 sal_snprintf(pname, SOC_PM_PHY_NAME_MAX_LEN-namelen-4, "%d", pcount); 4115 else if (pcount == 2) 4116 sal_snprintf(pname, SOC_PM_PHY_NAME_MAX_LEN-namelen-4, "%d-%d", (range_start-1)%4, ((range_start-1)%4)+1); 4117 else 4118 sal_snprintf(pname, SOC_PM_PHY_NAME_MAX_LEN-namelen-4, "%d", (range_start-1)%4); 4119 4120 return SOC_E_NONE; 4121 #else /* PORTMOD_SUPPORT */ 4122 return SOC_E_UNAVAIL; 4123 #endif /* PORTMOD_SUPPORT */ 4124 } 4125 4126 /* 4127 * Function: 4128 * soc_portctrl_port_mode_set 4129 * Purpose: 4130 * Set the port mode 4131 * Parameters: 4132 * unit - SOC Unit # 4133 * port - Port # 4134 * mode - port mode 4135 * Returns: 4136 * SOC_E_XXX 4137 */ 4138 int 4139 soc_portctrl_port_mode_set(int unit, int port, int mode) 4140 { 4141 #ifdef PORTMOD_SUPPORT 4142 portmod_port_mode_info_t port_mode_info; 4143 4144 portmod_port_mode_info_t_init(unit, &port_mode_info); 4145 4146 port_mode_info.cur_mode = mode; 4147 4148 return portmod_port_mode_set(unit, port, &port_mode_info); 4149 4150 #else /* PORTMOD_SUPPORT */ 4151 return SOC_E_UNAVAIL; 4152 #endif /* PORTMOD_SUPPORT */ 4153 } 4154 4155 /* 4156 * Function: 4157 * soc_portctrl_port_mode_get 4158 * Purpose: 4159 * Get the port mode 4160 * Parameters: 4161 * unit - SOC Unit # 4162 * port - Port # 4163 * mode - port mode 4164 * lanes - lanes of the port 4165 * Returns: 4166 * SOC_E_XXX 4167 */ 4168 int 4169 soc_portctrl_port_mode_get(int unit, int port, int *mode, int *lanes) 4170 { 4171 #ifdef PORTMOD_SUPPORT 4172 int rv; 4173 portmod_port_mode_info_t port_mode_info; 4174 4175 portmod_port_mode_info_t_init(unit, &port_mode_info); 4176 4177 rv = portmod_port_mode_get(unit, port, &port_mode_info); 4178 4179 if (SOC_SUCCESS(rv)) { 4180 *mode = port_mode_info.cur_mode; 4181 *lanes = port_mode_info.lanes; 4182 } 4183 4184 return rv; 4185 4186 #else /* PORTMOD_SUPPORT */ 4187 return SOC_E_UNAVAIL; 4188 #endif /* PORTMOD_SUPPORT */ 4189 } 4190 4191 /* 4192 * Function: 4193 * soc_portctrl_phy_control_set 4194 * Purpose: 4195 * Set PHY specific configuration 4196 * Parameters: 4197 * unit - SOC Unit #. 4198 * port - Port number. 4199 * phyn - Phy number 4200 * phy_lane - Lane number 4201 * sys - Control set to be applied 4202 * on system side(1)or line side(0). 4203 * phy_ctrl - PHY control type to change 4204 * value - New setting for the PHY control 4205 * Returns: 4206 * SOC_E_XXX 4207 */ 4208 int 4209 soc_portctrl_phy_control_set(int unit, soc_port_t port, int phyn, 4210 int phy_lane, int sys_side, 4211 soc_phy_control_t phy_ctrl, uint32 value) 4212 { 4213 #ifdef PORTMOD_SUPPORT 4214 phymod_phy_access_t pm_acc; 4215 phymod_phy_access_t pm_acc12[3]; 4216 uint32_t saved_lane_mask[3]; 4217 int i=0; 4218 int num_pm_acc; 4219 portmod_access_get_params_t params; 4220 int is_legacy_ext_phy_present = 0; 4221 int per_lane_ctrl = 1; 4222 int ref_clk; 4223 int pport; 4224 portmod_dispatch_type_t pm_type; 4225 uint32_t port_dynamic_state = 0; 4226 4227 portmod_access_get_params_t_init(unit, ¶ms); 4228 4229 /* 4230 phyn == 0 ( outermost ) 4231 phyn == 1 ( internal ) 4232 phyn == >1 ( ext phy ) 4233 4234 portmod internal 4235 phyn == -1 (outermost ) 4236 phyn == 0 ( internal ) 4237 phyn == >=1 external phy# 4238 */ 4239 4240 if( phyn >= 1) { 4241 params.phyn = phyn-1; 4242 } else { 4243 params.phyn = -1; 4244 } 4245 4246 params.lane = phy_lane; 4247 params.sys_side = (sys_side == 1) ? PORTMOD_SIDE_SYSTEM : PORTMOD_SIDE_LINE; 4248 params.apply_lane_mask = 1; 4249 4250 if (IS_C_PORT(unit, port) || 4251 (IS_CXX_PORT(unit, port) && IS_CL_PORT(unit, port))) { 4252 SOC_IF_ERROR_RETURN 4253 (portmod_port_phy_lane_access_get(unit, port, ¶ms, 4254 3, &pm_acc12[0], &num_pm_acc, NULL)); 4255 /* if the phys are identical, consolidate lane mask and run once. */ 4256 if ( num_pm_acc == 3 ){ 4257 for(i=0; i < num_pm_acc; i++) { 4258 saved_lane_mask[i] = pm_acc12[i].access.lane_mask; 4259 pm_acc12[i].access.lane_mask = 0; /* need this to do compare. */ 4260 } 4261 4262 if( !sal_memcmp( &pm_acc12[0],&pm_acc12[1], sizeof(phymod_phy_access_t)) && 4263 !sal_memcmp( &pm_acc12[0],&pm_acc12[2], sizeof(phymod_phy_access_t))){ 4264 pm_acc12[0].access.lane_mask = ( saved_lane_mask[0]| saved_lane_mask[1]| saved_lane_mask[2]); 4265 phymod_access_t_init(&pm_acc12[1].access); 4266 phymod_access_t_init(&pm_acc12[2].access); 4267 /* cli_out("Consolidating entries.\n");*/ 4268 num_pm_acc = 1; 4269 } else { 4270 /* restore lane mask */ 4271 for(i=0; i < num_pm_acc; i++) { 4272 pm_acc12[i].access.lane_mask = saved_lane_mask[i]; 4273 } 4274 } 4275 } 4276 4277 } else { 4278 SOC_IF_ERROR_RETURN 4279 (portmod_port_phy_lane_access_get(unit, port, ¶ms, 4280 1, &pm_acc, &num_pm_acc, NULL)); 4281 } 4282 4283 if (num_pm_acc == 0) { 4284 return SOC_E_FAIL; 4285 } 4286 4287 SOC_IF_ERROR_RETURN 4288 (portmod_port_ref_clk_get(unit, port, &ref_clk)); 4289 4290 switch (phy_ctrl) { 4291 /* Not per lane control */ 4292 case SOC_PHY_CONTROL_LANE_SWAP: 4293 per_lane_ctrl = 0; 4294 break; 4295 default: 4296 break; 4297 } 4298 4299 /* only check if phy is legacy when phyn is not 0 (in portmod internal phy is always not legacy) */ 4300 if(params.phyn != 0) { 4301 SOC_IF_ERROR_RETURN( 4302 portmod_port_is_legacy_ext_phy_present(unit, port, &is_legacy_ext_phy_present)); 4303 } 4304 4305 if(!is_legacy_ext_phy_present) { 4306 if (IS_C_PORT(unit, port) || 4307 (IS_CXX_PORT(unit, port) && IS_CL_PORT(unit, port))) { 4308 if (phy_ctrl == SOC_PHY_CONTROL_CL72) { 4309 SOC_IF_ERROR_RETURN 4310 (portmod_port_pm_type_get(unit, port, &pport, &pm_type)); 4311 #if defined(PORTMOD_PM12X10_SUPPORT) 4312 if (pm_type == portmodDispatchTypePm12x10) { 4313 SOC_IF_ERROR_RETURN ( 4314 portmod_port_cl72_set(unit, port, value)); 4315 return SOC_E_NONE; 4316 } 4317 #endif 4318 } 4319 SOC_IF_ERROR_RETURN( 4320 soc_port_control_set_wrapper(unit, ref_clk, per_lane_ctrl, 4321 &pm_acc12[0], num_pm_acc, phy_ctrl, value)); 4322 } else { 4323 if (phy_ctrl != SOC_PHY_CONTROL_AUTONEG_MODE) { 4324 SOC_IF_ERROR_RETURN( 4325 soc_port_control_set_wrapper(unit, ref_clk, per_lane_ctrl, 4326 &pm_acc, 1, phy_ctrl, value)); 4327 } 4328 } 4329 } else { 4330 SOC_IF_ERROR_RETURN( 4331 portmod_port_ext_phy_control_set(unit, port, phyn, phy_lane, sys_side, 4332 phy_ctrl, value)); 4333 } 4334 4335 /* update the state in portmod */ 4336 switch(phy_ctrl) { 4337 case SOC_PHY_CONTROL_AUTONEG_MODE: 4338 PORTMOD_PORT_AUTONEG_MODE_UPDATED_SET(port_dynamic_state); 4339 port_dynamic_state |= value << 16; 4340 portmod_port_update_dynamic_state(unit, port, port_dynamic_state); 4341 break; 4342 case SOC_PHY_CONTROL_TX_FIR_PRE: 4343 case SOC_PHY_CONTROL_TX_FIR_MAIN: 4344 case SOC_PHY_CONTROL_TX_FIR_POST: 4345 case SOC_PHY_CONTROL_TX_FIR_POST2: 4346 case SOC_PHY_CONTROL_TX_FIR_POST3: 4347 case SOC_PHY_CONTROL_PREEMPHASIS: 4348 case SOC_PHY_CONTROL_DRIVER_CURRENT: 4349 PORTMOD_PORT_DEFAULT_TX_PARAMS_UPDATED_SET(port_dynamic_state); 4350 portmod_port_update_dynamic_state(unit, port, port_dynamic_state); 4351 break; 4352 default: 4353 break; 4354 } 4355 4356 return SOC_E_NONE; 4357 4358 #else /* PORTMOD_SUPPORT */ 4359 return SOC_E_UNAVAIL; 4360 #endif /* PORTMOD_SUPPORT */ 4361 } 4362 4363 /* 4364 * Function: 4365 * soc_portctrl_phy_control_get 4366 * Purpose: 4367 * Get PHY specific configuration 4368 * Parameters: 4369 * unit - SOC Unit #. 4370 * port - Port number. 4371 * phyn - Phy number 4372 * phy_lane - Lane number 4373 * sys - Control get to be applied 4374 * on system side(1)or line side(0). 4375 * phy_ctrl - PHY control type to read 4376 * value - Current setting for the PHY control 4377 * Returns: 4378 * SOC_E_XXX 4379 */ 4380 int 4381 soc_portctrl_phy_control_get(int unit, soc_port_t port, int phyn, 4382 int phy_lane, int sys_side, 4383 soc_phy_control_t phy_ctrl, uint32 *value) 4384 { 4385 #ifdef PORTMOD_SUPPORT 4386 phymod_phy_access_t pm_acc, pm12_acc[3]; 4387 uint32_t saved_lane_mask[3]; 4388 int i=0; 4389 int num_pm_acc; 4390 portmod_access_get_params_t params; 4391 int is_legacy_ext_phy = 0; 4392 int per_lane_ctrl = 1; 4393 int ref_clk; 4394 4395 portmod_access_get_params_t_init(unit, ¶ms); 4396 4397 /* 4398 phyn == -1 ( outermost phy GPORT 0 get converted to -1) 4399 phyn == 1 ( internal ) 4400 phyn == >1 ( ext phy ) 4401 4402 portmod internal 4403 phyn == -1 (outermost ) 4404 phyn == 0 ( internal ) 4405 phyn == >=1 external phy# 4406 */ 4407 if( phyn >= 1) { 4408 params.phyn = phyn-1; 4409 } else { 4410 params.phyn = -1; 4411 } 4412 4413 params.lane = phy_lane; 4414 params.apply_lane_mask = 1; 4415 params.sys_side = (sys_side == 1) ? PORTMOD_SIDE_SYSTEM : PORTMOD_SIDE_LINE; 4416 4417 if (IS_C_PORT(unit, port) || 4418 (IS_CXX_PORT(unit, port) && IS_CL_PORT(unit, port))) { 4419 SOC_IF_ERROR_RETURN 4420 (portmod_port_phy_lane_access_get(unit, port, ¶ms, 4421 3, &pm12_acc[0], &num_pm_acc, NULL)); 4422 4423 /* if the phys are identical, consolidate lane mask and run once. */ 4424 if ( num_pm_acc == 3 ){ 4425 for(i=0; i < num_pm_acc; i++) { 4426 saved_lane_mask[i] = pm12_acc[i].access.lane_mask; 4427 pm12_acc[i].access.lane_mask = 0; /* need this to do compare. */ 4428 } 4429 if( !sal_memcmp( &pm12_acc[0],&pm12_acc[1], sizeof(phymod_phy_access_t)) && 4430 !sal_memcmp( &pm12_acc[0],&pm12_acc[2], sizeof(phymod_phy_access_t))){ 4431 pm12_acc[0].access.lane_mask = ( saved_lane_mask[0]| saved_lane_mask[1]| saved_lane_mask[2]); 4432 phymod_access_t_init(&pm12_acc[1].access); 4433 phymod_access_t_init(&pm12_acc[2].access); 4434 /* cli_out("Consolidating entries.\n");*/ 4435 num_pm_acc = 1; 4436 } else { 4437 /* restore lane mask */ 4438 for(i=0; i < num_pm_acc; i++) { 4439 pm12_acc[i].access.lane_mask = saved_lane_mask[i]; 4440 } 4441 } 4442 } 4443 } else { 4444 SOC_IF_ERROR_RETURN 4445 (portmod_port_phy_lane_access_get(unit, port, ¶ms, 4446 1, &pm_acc, &num_pm_acc, NULL)); 4447 } 4448 if (IS_CPRI_PORT(unit, port)) { 4449 if(phy_ctrl==SOC_PHY_CONTROL_EEE) { 4450 return SOC_E_UNAVAIL; 4451 } 4452 } 4453 if (num_pm_acc == 0) { 4454 return SOC_E_FAIL; 4455 } 4456 4457 SOC_IF_ERROR_RETURN 4458 (portmod_port_ref_clk_get(unit, port, &ref_clk)); 4459 4460 switch (phy_ctrl) { 4461 /* Not per lane control */ 4462 case SOC_PHY_CONTROL_LANE_SWAP: 4463 per_lane_ctrl = 0; 4464 break; 4465 case SOC_PHY_CONTROL_FEC_CORRECTED_CODEWORD_COUNT: 4466 per_lane_ctrl = 0; 4467 break; 4468 case SOC_PHY_CONTROL_FEC_UNCORRECTED_CODEWORD_COUNT: 4469 per_lane_ctrl = 0; 4470 break; 4471 default: 4472 break; 4473 } 4474 4475 /* only check if phy is legacy when phyn is not 0 (in portmod internal phy is always not legacy) */ 4476 if(params.phyn != 0) { 4477 SOC_IF_ERROR_RETURN( 4478 portmod_port_is_legacy_ext_phy_present(unit, port, &is_legacy_ext_phy)); 4479 } 4480 4481 if (!is_legacy_ext_phy) { 4482 if (IS_C_PORT(unit, port) || 4483 (IS_CXX_PORT(unit, port) && IS_CL_PORT(unit, port))) { 4484 SOC_IF_ERROR_RETURN( 4485 soc_port_control_get_wrapper(unit, ref_clk, per_lane_ctrl, 4486 &pm12_acc[0], num_pm_acc, phy_ctrl, value)); 4487 } else { 4488 SOC_IF_ERROR_RETURN( 4489 soc_port_control_get_wrapper(unit, ref_clk, per_lane_ctrl, 4490 &pm_acc, 1, phy_ctrl, value)); 4491 } 4492 } else { 4493 /* Legacy ext PHYs do not support CL91, below we return SOC_E_UNAVAIL */ 4494 if (phy_ctrl == SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION_CL91) { 4495 return SOC_E_UNAVAIL; 4496 } 4497 4498 SOC_IF_ERROR_RETURN( 4499 portmod_port_ext_phy_control_get(unit, port, phyn, phy_lane, sys_side, 4500 phy_ctrl, value)); 4501 } 4502 4503 return SOC_E_NONE; 4504 4505 #else /* PORTMOD_SUPPORT */ 4506 return SOC_E_UNAVAIL; 4507 #endif /* PORTMOD_SUPPORT */ 4508 } 4509 4510 /* 4511 * Function: 4512 * soc_portctrl_phy_timesync_config_set 4513 * Purpose: 4514 * Set timesync config 4515 * Parameters: 4516 * unit - SOC Unit #. 4517 * port - Port number. 4518 * phyn - Phy number 4519 * Returns: 4520 * SOC_E_XXX 4521 */ 4522 int 4523 soc_portctrl_phy_timesync_config_set(int unit, soc_port_t port, 4524 soc_port_phy_timesync_config_t *conf) 4525 { 4526 #ifdef PORTMOD_SUPPORT 4527 int rv; 4528 4529 INT_MCU_LOCK(unit); 4530 rv = portmod_port_timesync_config_set(unit, port, conf); 4531 INT_MCU_UNLOCK(unit); 4532 4533 if (SOC_FAILURE(rv)) { 4534 LOG_WARN(BSL_LS_SOC_PORT, 4535 (BSL_META_U(unit, 4536 "_soc_portctrl_phy_timesync_config_set failed %d\n"), rv)); 4537 } 4538 return rv; 4539 #else /* PORTMOD_SUPPORT */ 4540 return SOC_E_UNAVAIL; 4541 #endif /* PORTMOD_SUPPORT */ 4542 } 4543 4544 /* 4545 * Function: 4546 * soc_portctrl_phy_timesync_config_set 4547 * Purpose: 4548 * Set timesync config 4549 * Parameters: 4550 * unit - SOC Unit #. 4551 * port - Port number. 4552 * phyn - Phy number 4553 * Returns: 4554 * SOC_E_XXX 4555 */ 4556 int 4557 soc_portctrl_phy_timesync_config_get(int unit, soc_port_t port, 4558 soc_port_phy_timesync_config_t *conf) 4559 { 4560 #ifdef PORTMOD_SUPPORT 4561 int rv; 4562 4563 INT_MCU_LOCK(unit); 4564 rv = portmod_port_timesync_config_get(unit, port, conf); 4565 INT_MCU_UNLOCK(unit); 4566 4567 if (SOC_FAILURE(rv)) { 4568 LOG_WARN(BSL_LS_SOC_PORT, 4569 (BSL_META_U(unit, 4570 "_soc_portctrl_phy_timesync_config_get failed %d\n"), rv)); 4571 } 4572 return rv; 4573 #else /* PORTMOD_SUPPORT */ 4574 return SOC_E_UNAVAIL; 4575 #endif /* PORTMOD_SUPPORT */ 4576 } 4577 4578 /* 4579 * Function: 4580 * soc_portctrl_control_phy_timesync_config_set 4581 * Purpose: 4582 * Set timesync config 4583 * Parameters: 4584 * unit - SOC Unit #. 4585 * port - Port number. 4586 * phyn - Phy number 4587 * Returns: 4588 * SOC_E_XXX 4589 */ 4590 int 4591 soc_portctrl_control_phy_timesync_set(int unit, soc_port_t port, 4592 soc_port_control_phy_timesync_t type, 4593 uint64 value) 4594 { 4595 #ifdef PORTMOD_SUPPORT 4596 int rv; 4597 4598 INT_MCU_LOCK(unit); 4599 rv = portmod_port_control_phy_timesync_set(unit, port, type, value); 4600 INT_MCU_UNLOCK(unit); 4601 4602 if (SOC_FAILURE(rv)) { 4603 LOG_WARN(BSL_LS_SOC_PORT, 4604 (BSL_META_U(unit, 4605 "_soc_portctrl_control_phy_timesync_set failed %d\n"), rv)); 4606 } 4607 return rv; 4608 #else /* PORTMOD_SUPPORT */ 4609 return SOC_E_UNAVAIL; 4610 #endif /* PORTMOD_SUPPORT */ 4611 } 4612 4613 /* 4614 * Function: 4615 * soc_portctrl_control_phy_timesync_config_get 4616 * Purpose: 4617 * Set timesync config 4618 * Parameters: 4619 * unit - SOC Unit #. 4620 * port - Port number. 4621 * phyn - Phy number 4622 * Returns: 4623 * SOC_E_XXX 4624 */ 4625 int 4626 soc_portctrl_control_phy_timesync_get(int unit, soc_port_t port, 4627 soc_port_control_phy_timesync_t type, 4628 uint64 *value) 4629 { 4630 #ifdef PORTMOD_SUPPORT 4631 int rv; 4632 4633 INT_MCU_LOCK(unit); 4634 rv = portmod_port_control_phy_timesync_get(unit, port, type, value); 4635 INT_MCU_UNLOCK(unit); 4636 4637 if (SOC_FAILURE(rv)) { 4638 LOG_WARN(BSL_LS_SOC_PORT, 4639 (BSL_META_U(unit, 4640 "_soc_portctrl_phy_timesync_set failed %d\n"), rv)); 4641 } 4642 return rv; 4643 #else /* PORTMOD_SUPPORT */ 4644 return SOC_E_UNAVAIL; 4645 #endif /* PORTMOD_SUPPORT */ 4646 } 4647 4648 /* 4649 * Function: 4650 * soc_esw_portctrl_encap_get 4651 * Purpose: 4652 * Get the port encapsulation mode. 4653 * Parameters: 4654 * unit - (IN) Unit number. 4655 * port - (IN) Port number. 4656 * mode - (OUT) One of _SHR_PORT_ENCAP_xxx. 4657 * Returns: 4658 * SOC_E_XXX 4659 */ 4660 int 4661 soc_esw_portctrl_encap_get(int unit, soc_port_t port, int *mode) 4662 { 4663 #ifdef PORTMOD_SUPPORT 4664 int rv = SOC_E_NONE; 4665 int flags = 0; 4666 portctrl_pport_t pport; 4667 portmod_encap_t encap; 4668 4669 PORTCTRL_PORT_TO_PPORT(port, pport); 4670 4671 SOC_CONTROL_LOCK(unit); 4672 rv = portmod_port_encap_get(unit, pport, &flags, &encap); 4673 SOC_CONTROL_UNLOCK(unit); 4674 4675 if (PORTMOD_SUCCESS(rv)) { 4676 *mode = encap; 4677 } 4678 4679 return rv; 4680 4681 #else /* PORTMOD_SUPPORT */ 4682 return SOC_E_UNAVAIL; 4683 #endif /* PORTMOD_SUPPORT */ 4684 } 4685 4686 /* 4687 * Function: 4688 * soc_esw_portctrl_port_to_phyaddr 4689 * Purpose: 4690 * This function gets phy address associated with the port 4691 * Parameters: 4692 * unit - (IN) Unit number. 4693 * port - (IN) Port number. 4694 * Returns: 4695 * Phy address value 4696 */ 4697 int 4698 soc_esw_portctrl_port_to_phyaddr(int unit, soc_port_t port, uint8* phy_addr) 4699 { 4700 #ifdef PORTMOD_SUPPORT 4701 int addr; 4702 portctrl_pport_t pport; 4703 int rv = SOC_E_NONE; 4704 4705 PORTCTRL_PORT_TO_PPORT(port, pport); 4706 4707 SOC_CONTROL_LOCK(unit); 4708 addr = portmod_port_to_phyaddr(unit, pport); 4709 SOC_CONTROL_UNLOCK(unit); 4710 4711 /* Portmod API returns phy address on successful execution, and 4712 * negative value in case of error. 4713 * So we program phy_addr, rv accordingly 4714 */ 4715 /* coverity[negative_returns] */ 4716 if (addr >= 0) { 4717 *phy_addr = addr; 4718 } else { 4719 rv = addr; 4720 } 4721 4722 return rv; 4723 4724 #else /* PORTMOD_SUPPORT */ 4725 return SOC_E_UNAVAIL; 4726 #endif /* PORTMOD_SUPPORT */ 4727 } 4728 4729 /* 4730 * Function: 4731 * soc_esw_portctrl_speed_get 4732 * Purpose: 4733 * Get the port speed. 4734 * Parameters: 4735 * unit - (IN) Unit number. 4736 * port - (IN) Port number. 4737 * speed - (OUT) Port speed. 4738 * Returns: 4739 * SOC_E_XXX 4740 */ 4741 int 4742 soc_esw_portctrl_speed_get(int unit, soc_port_t port, int *speed) 4743 { 4744 #ifdef PORTMOD_SUPPORT 4745 int rv = SOC_E_NONE; 4746 portctrl_pport_t pport; 4747 portmod_port_interface_config_t portmod_if_config; 4748 4749 PORTCTRL_PORT_TO_PPORT(port, pport); 4750 4751 /* 4752 * Temporary solution until PortMod null driver is in place 4753 */ 4754 if (SOC_PBMP_MEMBER(SOC_PORT_DISABLED_BITMAP(unit,all), port)) { 4755 *speed = SOC_INFO(unit).port_speed_max[port]; 4756 return SOC_E_NONE; 4757 } 4758 4759 SOC_CONTROL_LOCK(unit); 4760 rv = portmod_port_interface_config_get(unit, pport, &portmod_if_config, PORTMOD_INIT_F_EXTERNAL_MOST_ONLY); 4761 SOC_CONTROL_UNLOCK(unit); 4762 4763 if (PORTMOD_SUCCESS(rv)) { 4764 *speed = portmod_if_config.speed; 4765 4766 if (IS_HG_PORT(unit, port) && *speed < 5000) { 4767 *speed = 0; 4768 } 4769 } 4770 4771 return rv; 4772 4773 #else /* PORTMOD_SUPPORT */ 4774 return SOC_E_UNAVAIL; 4775 #endif /* PORTMOD_SUPPORT */ 4776 } 4777 4778 /* 4779 * Function: 4780 * _soc_esw_portctrl_speed_slots_get 4781 * Purpose: 4782 * Get number of slots required for given port speed 4783 * Returns: 4784 * SOC_E_XXX 4785 */ 4786 STATIC int 4787 _soc_esw_portctrl_speed_slots_get(int unit, int speed) 4788 { 4789 int slot_num = 0; 4790 4791 switch(speed) { 4792 case 10: 4793 case 100: 4794 case 1000: 4795 case 2500: 4796 slot_num = 1; 4797 break; 4798 case 5000: 4799 case 10000: 4800 case 11000: 4801 slot_num = 4; 4802 break; 4803 case 13000: 4804 case 16000: 4805 if(SOC_IS_TITAN2PLUS(unit)){ 4806 slot_num = 8; 4807 } else { 4808 LOG_ERROR(BSL_LS_SOC_PORT, 4809 ("Unsupported port speed %d\n", speed)); 4810 } 4811 break; 4812 case 20000: 4813 case 21000: 4814 slot_num = 8; 4815 break; 4816 case 25000: 4817 case 25450: 4818 case 27000: 4819 slot_num = 10; 4820 break; 4821 case 40000: 4822 case 42000: 4823 slot_num = 16; 4824 break; 4825 case 50000: 4826 case 53000: 4827 slot_num = 20; 4828 break; 4829 case 100000: 4830 case 106000: 4831 slot_num = 40; 4832 break; 4833 case 120000: 4834 case 127000: 4835 slot_num = 48; 4836 break; 4837 default: 4838 LOG_ERROR(BSL_LS_SOC_PORT, 4839 ("Unsupported port speed %d\n", speed)); 4840 break; 4841 } 4842 4843 return (slot_num); 4844 } 4845 4846 /* 4847 * Function: 4848 * soc_port_is_same_speed_class 4849 * Purpose: 4850 * Check if pre,post speeds are same speed class 4851 * to know TDM reconfiguration is required or not. 4852 * Speed Class is defined as below 4853 * ------------------------- 4854 * | Group | Speeds | 4855 * |=======================| 4856 * | 0 | 1G, 2.5G | 4857 * | 1 | 10G, 11G | 4858 * | 2 | 20G, 21G | 4859 * | 3 | 25G, 27G | 4860 * | 4 | 40G, 42G | 4861 * | 5 | 100G, 106G | 4862 * | 6 | 120G, 127G | 4863 * ------------------------- 4864 * If speed group is different, then need to reconfigure TDM 4865 */ 4866 int 4867 soc_esw_portctrl_is_same_speed_class(int unit, int pre_speed, int post_speed) 4868 { 4869 int rv; 4870 int pre_slot, post_slot; 4871 4872 pre_slot = _soc_esw_portctrl_speed_slots_get(unit, pre_speed); 4873 post_slot = _soc_esw_portctrl_speed_slots_get(unit, post_speed); 4874 4875 if (pre_slot == post_slot) { 4876 rv = TRUE; 4877 } else { 4878 rv = FALSE; 4879 } 4880 4881 return rv; 4882 } 4883 4884 /* 4885 * Function: 4886 * soc_esw_portctrl_port_ability_update 4887 * Purpose: 4888 * Update supported abilities of a port 4889 * Parameters: 4890 * unit - StrataSwitch unit # 4891 * port - StrataSwitch port # 4892 * ability - (OUT) Returns updated soc_port_ability_t structure information. 4893 * 4894 * Returns: 4895 * SOC_E_XXX 4896 */ 4897 soc_error_t 4898 soc_esw_portctrl_port_ability_update(int unit, soc_port_t port, soc_port_ability_t *ability) 4899 { 4900 int rv = SOC_E_NONE; 4901 #ifdef PORTMOD_SUPPORT 4902 if ((SOC_PORTCTRL_FUNCTIONS(unit)) && 4903 (SOC_PORTCTRL_FUNCTIONS(unit)->soc_portctrl_port_ability_update)) { 4904 rv = SOC_PORTCTRL_FUNCTIONS(unit)->soc_portctrl_port_ability_update(unit, port, ability); 4905 } else { 4906 rv = SOC_E_NONE; 4907 } 4908 return rv; 4909 #else 4910 return rv; 4911 #endif 4912 } 4913 4914 /* 4915 * Function: 4916 * soc_esw_portctrl_pll_div_get 4917 * Purpose: 4918 * Get VCO frequency(PLL div) for port. 4919 * PLL DIV value can be converted to VCO frequency by following equation. 4920 * VCO = (PLL_DIV) * (REF_CLK) 4921 * 4922 * Here is the complete table for TSCE(TD2+) 4923 * ---------------------------------------------------------- 4924 * | encap type | speed | lanes | VCO | PLL_DIV | REF_CLK 4925 * | IEEE | 1 | 1 | 10312.5 | 66 | 156.25 4926 * | IEEE | 1 | 1 | 6250 | 40 | 156.25 4927 * | IEEE | 2.5 | 1 | 6250 | 40 | 156.25 4928 * | IEEE | 10 | 1 | 10312.5 | 66 | 156.25 4929 * | HIGIG2 | 10 | 1 | 10312.5 | 66 | 156.25 4930 * | HIGIG2 | 11 | 1 | 10937.5 | 70 | 156.25 4931 * | IEEE | 20 | 2 | 10312.5 | 66 | 156.25 4932 * | HIGIG2 | 20 | 2 | 10312.5 | 66 | 156.25 4933 * | HIGIG2 | 21 | 2 | 10937.5 | 70 | 156.25 4934 * | IEEE | 10 | 4 | 6250 | 40 | 156.25 4935 * | HIGIG2 | 10 | 4 | 6250 | 40 | 156.25 4936 * | HIGIG2 | 11 | 4 | 6562.5 | 42 | 156.25 4937 * | IEEE | 40 | 4 | 10312.5 | 66 | 156.25 4938 * | HIGIG2 | 40 | 4 | 10312.5 | 66 | 156.25 4939 * | HIGIG2 | 42 | 4 | 10937.5 | 70 | 156.25 4940 * | IEEE | 100 | 10 | 10312.5 | 66 | 156.25 4941 * | HIGIG2 | 100 | 10 | 10312.5 | 66 | 156.25 4942 * | HIGIG2 | 106 | 10 | 10937.5 | 70 | 156.25 4943 * | IEEE | 120 | 12 | 10312.5 | 66 | 156.25 4944 * | HIGIG2 | 127 | 12 | 10937.5 | 70 | 156.25 4945 * ---------------------------------------------------------- 4946 * 4947 * Parameters: 4948 * unit - (IN) Unit number 4949 * logic_port - (IN) logical port number 4950 * phy_port - (IN) Physical port number 4951 * speed - (IN) Speed 4952 * num_lane - (IN) Number of lanes 4953 * encap - (IN) Encap mode 4954 * pll_div - (OUT) pll div 4955 * Returns: 4956 * Note: 4957 */ 4958 /*In flex port, there are some logic ports are generated. And the new ports is not initialized in Add SOC_INFO(unit).port_p2l_mapping. 4959 That is to say we can`t retrieve the logical port via physical port. 4960 */ 4961 int 4962 soc_esw_portctrl_pll_div_get(int unit, soc_port_t logic_port, soc_port_t phy_port, 4963 int speed, int num_lane, int encap, 4964 uint32 *pll_div) 4965 { 4966 #ifdef PORTMOD_SUPPORT 4967 int rv; 4968 portmod_port_resources_t pr; 4969 int serdes_1000x_at_25g_vco = 0; 4970 int serdes_10g_at_25g_vco = 0; 4971 int serdes_1000x_at_6250_vco = 0; 4972 int serdes_1000x_at_12500_vco = 0; 4973 4974 #if (defined BCM_HELIX5_SUPPORT) || (defined BCM_MAVERICK2_SUPPORT) 4975 if (SOC_IS_HELIX5(unit) || 4976 (SOC_IS_MAVERICK2(unit) && SOC_INFO(unit).bandwidth == 2000000)) { 4977 serdes_1000x_at_25g_vco = 1; 4978 serdes_10g_at_25g_vco = 1; 4979 } 4980 #endif 4981 pr.flag = 0; 4982 /*In flex port, customer can configure the following properties to select pll DIV for the new generated ports. 4983 So we need to parse these properties here directly. 4984 */ 4985 serdes_1000x_at_6250_vco = 4986 soc_property_port_get(unit, logic_port, 4987 spn_SERDES_1000X_AT_6250_VCO, serdes_1000x_at_6250_vco); 4988 if (serdes_1000x_at_6250_vco) { 4989 PORTMOD_SERDES_1000X_AT_6250_SET(pr.flag); 4990 } 4991 4992 serdes_1000x_at_12500_vco = 4993 soc_property_port_get(unit, logic_port, 4994 spn_SERDES_1000X_AT_12500_VCO, serdes_1000x_at_12500_vco); 4995 if (serdes_1000x_at_12500_vco) { 4996 PORTMOD_SERDES_1000X_AT_12500_SET(pr.flag); 4997 } 4998 4999 serdes_1000x_at_25g_vco = 5000 soc_property_port_get(unit, logic_port, 5001 spn_SERDES_1000X_AT_25G_VCO, serdes_1000x_at_25g_vco); 5002 if (serdes_1000x_at_25g_vco) { 5003 PORTMOD_SERDES_1000X_AT_25G_SET(pr.flag); 5004 } 5005 5006 serdes_10g_at_25g_vco = 5007 soc_property_port_get(unit, logic_port, 5008 spn_SERDES_10G_AT_25G_VCO, serdes_10g_at_25g_vco); 5009 if (serdes_10g_at_25g_vco) { 5010 PORTMOD_SERDES_10G_AT_25G_SET(pr.flag); 5011 } 5012 5013 pr.speed = speed; 5014 pr.num_lane = num_lane; 5015 pr.encap_mode = encap; 5016 5017 SOC_CONTROL_LOCK(unit); 5018 rv = portmod_pm_port_pll_div_get(unit, logic_port, phy_port, &pr, pll_div); 5019 SOC_CONTROL_UNLOCK(unit); 5020 if (PORTMOD_FAILURE(rv)) { 5021 LOG_ERROR(BSL_LS_SOC_PORT, (BSL_META_U(unit, 5022 "Failed to get pll_div\n"))); 5023 return rv; 5024 } 5025 5026 return SOC_E_NONE; 5027 #else /* PORTMOD_SUPPORT */ 5028 return SOC_E_UNAVAIL; 5029 #endif /* PORTMOD_SUPPORT */ 5030 } 5031 5032 /* 5033 * Function: 5034 * soc_esw_portmod_port_vcos_get 5035 * Purpose: 5036 * Verify if the given port combination is supported on a port macro 5037 * Parameters: 5038 * unit - StrataSwitch unit # 5039 * phy_port - array of ports in given port macro # 5040 * lanes - lanes for each port in given port macro # 5041 * speed - speed of each port in port macro # 5042 * encap - encap of each port in port macro # 5043 * size - no of ports in port macro # 5044 * 5045 * Returns: 5046 * SOC_E_XXX 5047 */ 5048 #ifdef PORTMOD_SUPPORT 5049 int 5050 soc_esw_portmod_port_vcos_get(int unit, soc_port_t phy_port, 5051 portmod_dispatch_type_t pm_type, int* lanes, 5052 int* speed, int* encap, int size) 5053 { 5054 5055 #ifdef PORTMOD_CPM4X25_SUPPORT 5056 portmod_vcos_speed_config_t speed_config_list[4]; 5057 portmod_dual_vcos_t dual_vco; 5058 int ethernet = 0 ; 5059 int cpri = 0 ; 5060 int i = 0 ; 5061 int rv = 0; 5062 5063 if ((pm_type != portmodDispatchTypePm4x25) && (pm_type != portmodDispatchTypeCpm4x25)) { 5064 LOG_ERROR(BSL_LS_SOC_PORT, (BSL_META_U(unit, 5065 "soc_esw_portmod_port_vcos_get not supported for pm_type %d\n"), pm_type)); 5066 } 5067 for (i = 0 ; i < size ; i++) { 5068 speed_config_list[i].speed = speed[i]; 5069 speed_config_list[i].num_lanes = lanes[i]; 5070 speed_config_list[i].eth_of_mixed_mode = 0; 5071 speed_config_list[i].higig_mode = 0; 5072 speed_config_list[i].ieee_mode = 0; 5073 if (encap[i] == SOC_ENCAP_IEEE) { 5074 speed_config_list[i].ieee_mode = 1; 5075 speed_config_list[i].port_type = portmodCpmPrtEthMode; 5076 ethernet = 1; 5077 } else if (encap[i] == SOC_ENCAP_CPRI) { 5078 speed_config_list[i].port_type = portmodCpmPrtCpriMode; 5079 cpri = 1 ; 5080 } else if (encap[i] == SOC_ENCAP_RSVD4) { 5081 speed_config_list[i].port_type = portmodCpmPrtRsvd4Mode; 5082 cpri = 1 ; 5083 } else if ((encap[i] == SOC_ENCAP_HIGIG) || (encap[i] == SOC_ENCAP_HIGIG2)) { 5084 speed_config_list[i].higig_mode = 1; 5085 speed_config_list[i].port_type = portmodCpmPrtEthMode; 5086 ethernet = 1; 5087 } 5088 5089 } 5090 if (ethernet && cpri) { 5091 for (i = 0 ; i < size ; i++) { 5092 if ((encap[i] == SOC_ENCAP_IEEE) || (encap[i] == SOC_ENCAP_HIGIG) || (encap[i] == SOC_ENCAP_HIGIG2) ) { 5093 speed_config_list[i].eth_of_mixed_mode = 1; 5094 speed_config_list[i].port_type = portmodCpmPrtEthOfMixedMode; 5095 } else if (speed_config_list[i].port_type == portmodCpmPrtCpriMode) { 5096 speed_config_list[i].port_type = portmodCpmPrtCpriOfMixedMode; 5097 } else if (speed_config_list[i].port_type == portmodCpmPrtRsvd4Mode) { 5098 speed_config_list[i].port_type = portmodCpmPrtRsvd4OfMixedMode; 5099 } 5100 } 5101 } 5102 portmod_dual_vcos_t_init(unit , &dual_vco); 5103 rv = portmod_pm_supported_vcos_get(unit, phy_port, pm_type, speed_config_list, size, &dual_vco); 5104 if (PORTMOD_FAILURE(rv)) { 5105 LOG_ERROR(BSL_LS_SOC_PORT, (BSL_META_U(unit, 5106 "Failed to get dual_vcos\n"))); 5107 return rv; 5108 } 5109 return SOC_E_NONE; 5110 #else /* PORTMOD_CPM4X25_SUPPORT */ 5111 return SOC_E_UNAVAIL; 5112 #endif /* PORTMOD_CPM4X25_SUPPORT */ 5113 } 5114 #endif /* PORTMOD_SUPPORT */ 5115 5116 int 5117 soc_esw_portctrl_phy_tx_set(int unit, soc_port_t port, 5118 int phyn, int phy_lane, 5119 int sys_side, soc_port_phy_tx_t *tx) 5120 { 5121 #ifdef PORTMOD_SUPPORT 5122 int rv = SOC_E_NONE; 5123 phymod_tx_t phy_tx; 5124 int nof_phys; 5125 portmod_access_get_params_t params; 5126 phymod_phy_access_t phy_access; 5127 5128 sal_memset(&phy_tx, 0, sizeof(phymod_tx_t)); 5129 portmod_access_get_params_t_init(unit, ¶ms); 5130 phymod_phy_access_t_init(&phy_access); 5131 5132 params.lane = phy_lane; 5133 SOC_IF_ERROR_RETURN 5134 (portmod_port_phy_lane_access_get(unit, port, ¶ms, 1, &phy_access, &nof_phys, NULL)); 5135 5136 /* convert from soc structure to phymod structure */ 5137 phy_tx.pre = tx->pre; 5138 phy_tx.main = tx->main; 5139 phy_tx.post = tx->post; 5140 phy_tx.post2 = tx->post2; 5141 phy_tx.post3 = tx->post3; 5142 phy_tx.pre2 = tx->pre2; 5143 5144 /* Enums for tap mode and signalling mode differ between SDK and portmod */ 5145 switch(tx->tx_tap_mode) { 5146 case socPortPhyTxTapMode3Tap: 5147 phy_tx.tap_mode = phymodTxTapMode3Tap; 5148 break; 5149 case socPortPhyTxTapMode6Tap: 5150 phy_tx.tap_mode = phymodTxTapMode6Tap; 5151 break; 5152 default: 5153 return SOC_E_PARAM; 5154 } 5155 switch(tx->signalling_mode) { 5156 case socPortPhySignallingModeNRZ: 5157 phy_tx.sig_method = phymodSignallingMethodNRZ; 5158 break; 5159 case socPortPhySignallingModePAM4: 5160 phy_tx.sig_method = phymodSignallingMethodPAM4; 5161 break; 5162 default: 5163 return SOC_E_INTERNAL; 5164 } 5165 5166 SOC_IF_ERROR_RETURN 5167 (soc_portctrl_phy_tx_set(unit, &phy_access, &phy_tx)); 5168 5169 return rv; 5170 #else 5171 return SOC_E_UNAVAIL; 5172 #endif 5173 } 5174 5175 int 5176 soc_esw_portctrl_phy_tx_get(int unit, soc_port_t port, 5177 int phyn, int phy_lane, 5178 int sys_side, soc_port_phy_tx_t *tx) 5179 { 5180 #ifdef PORTMOD_SUPPORT 5181 int rv = SOC_E_NONE; 5182 phymod_tx_t phy_tx; 5183 int nof_phys; 5184 portmod_access_get_params_t params; 5185 phymod_phy_access_t phy_access; 5186 5187 portmod_access_get_params_t_init(unit, ¶ms); 5188 phymod_phy_access_t_init(&phy_access); 5189 5190 params.lane = phy_lane; 5191 SOC_IF_ERROR_RETURN 5192 (portmod_port_phy_lane_access_get(unit, port, ¶ms, 1, &phy_access, &nof_phys, NULL)); 5193 5194 SOC_IF_ERROR_RETURN 5195 (soc_portctrl_phy_tx_get(unit, &phy_access, &phy_tx)); 5196 5197 /* convert from phymod structure to soc structure */ 5198 if (SOC_SUCCESS(rv)) { 5199 tx->pre2 = phy_tx.pre2; 5200 tx->pre = phy_tx.pre; 5201 tx->main = phy_tx.main; 5202 tx->post = phy_tx.post; 5203 tx->post2 = phy_tx.post2; 5204 tx->post3 = phy_tx.post3; 5205 5206 /* Enums for tap mode and signalling mode differ between 5207 * SDK and portmod */ 5208 switch(phy_tx.tap_mode) { 5209 case phymodTxTapMode3Tap: 5210 tx->tx_tap_mode = socPortPhyTxTapMode3Tap; 5211 break; 5212 case phymodTxTapMode6Tap: 5213 tx->tx_tap_mode = socPortPhyTxTapMode6Tap; 5214 break; 5215 default: 5216 return SOC_E_INTERNAL; 5217 } 5218 switch(phy_tx.sig_method) { 5219 case phymodSignallingMethodNRZ: 5220 tx->signalling_mode = socPortPhySignallingModeNRZ; 5221 break; 5222 case phymodSignallingMethodPAM4: 5223 tx->signalling_mode = socPortPhySignallingModePAM4; 5224 break; 5225 default: 5226 return SOC_E_INTERNAL; 5227 } 5228 } 5229 return rv; 5230 #else 5231 return SOC_E_UNAVAIL; 5232 #endif 5233 }