1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /* Copyright (c) 2020 Mellanox Technologies. All rights reserved */ 3 4 #include "reg.h" 5 #include "core.h" 6 #include "spectrum.h" 7 #include "core_env.h" 8 9 static const char mlxsw_sp_driver_version[] = "1.0"; 10 11 static void mlxsw_sp_port_get_drvinfo(struct net_device *dev, 12 struct ethtool_drvinfo *drvinfo) 13 { 14 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 15 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 16 17 strlcpy(drvinfo->driver, mlxsw_sp->bus_info->device_kind, 18 sizeof(drvinfo->driver)); 19 strlcpy(drvinfo->version, mlxsw_sp_driver_version, 20 sizeof(drvinfo->version)); 21 snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), 22 "%d.%d.%d", 23 mlxsw_sp->bus_info->fw_rev.major, 24 mlxsw_sp->bus_info->fw_rev.minor, 25 mlxsw_sp->bus_info->fw_rev.subminor); 26 strlcpy(drvinfo->bus_info, mlxsw_sp->bus_info->device_name, 27 sizeof(drvinfo->bus_info)); 28 } 29 30 struct mlxsw_sp_ethtool_link_ext_state_opcode_mapping { 31 u32 status_opcode; 32 enum ethtool_link_ext_state link_ext_state; 33 u8 link_ext_substate; 34 }; 35 36 static const struct mlxsw_sp_ethtool_link_ext_state_opcode_mapping 37 mlxsw_sp_link_ext_state_opcode_map[] = { 38 {2, ETHTOOL_LINK_EXT_STATE_AUTONEG, 39 ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED}, 40 {3, ETHTOOL_LINK_EXT_STATE_AUTONEG, 41 ETHTOOL_LINK_EXT_SUBSTATE_AN_ACK_NOT_RECEIVED}, 42 {4, ETHTOOL_LINK_EXT_STATE_AUTONEG, 43 ETHTOOL_LINK_EXT_SUBSTATE_AN_NEXT_PAGE_EXCHANGE_FAILED}, 44 {36, ETHTOOL_LINK_EXT_STATE_AUTONEG, 45 ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED_FORCE_MODE}, 46 {38, ETHTOOL_LINK_EXT_STATE_AUTONEG, 47 ETHTOOL_LINK_EXT_SUBSTATE_AN_FEC_MISMATCH_DURING_OVERRIDE}, 48 {39, ETHTOOL_LINK_EXT_STATE_AUTONEG, 49 ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_HCD}, 50 51 {5, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE, 52 ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_FRAME_LOCK_NOT_ACQUIRED}, 53 {6, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE, 54 ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_INHIBIT_TIMEOUT}, 55 {7, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE, 56 ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_PARTNER_DID_NOT_SET_RECEIVER_READY}, 57 {8, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE, 0}, 58 {14, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE, 59 ETHTOOL_LINK_EXT_SUBSTATE_LT_REMOTE_FAULT}, 60 61 {9, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH, 62 ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_BLOCK_LOCK}, 63 {10, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH, 64 ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_AM_LOCK}, 65 {11, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH, 66 ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_GET_ALIGN_STATUS}, 67 {12, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH, 68 ETHTOOL_LINK_EXT_SUBSTATE_LLM_FC_FEC_IS_NOT_LOCKED}, 69 {13, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH, 70 ETHTOOL_LINK_EXT_SUBSTATE_LLM_RS_FEC_IS_NOT_LOCKED}, 71 72 {15, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY, 0}, 73 {17, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY, 74 ETHTOOL_LINK_EXT_SUBSTATE_BSI_LARGE_NUMBER_OF_PHYSICAL_ERRORS}, 75 {42, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY, 76 ETHTOOL_LINK_EXT_SUBSTATE_BSI_UNSUPPORTED_RATE}, 77 78 {1024, ETHTOOL_LINK_EXT_STATE_NO_CABLE, 0}, 79 80 {16, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE, 81 ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE}, 82 {20, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE, 83 ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE}, 84 {29, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE, 85 ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE}, 86 {1025, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE, 87 ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE}, 88 {1029, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE, 89 ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE}, 90 {1031, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE, 0}, 91 92 {1027, ETHTOOL_LINK_EXT_STATE_EEPROM_ISSUE, 0}, 93 94 {23, ETHTOOL_LINK_EXT_STATE_CALIBRATION_FAILURE, 0}, 95 96 {1032, ETHTOOL_LINK_EXT_STATE_POWER_BUDGET_EXCEEDED, 0}, 97 98 {1030, ETHTOOL_LINK_EXT_STATE_OVERHEAT, 0}, 99 }; 100 101 static void 102 mlxsw_sp_port_set_link_ext_state(struct mlxsw_sp_ethtool_link_ext_state_opcode_mapping 103 link_ext_state_mapping, 104 struct ethtool_link_ext_state_info *link_ext_state_info) 105 { 106 switch (link_ext_state_mapping.link_ext_state) { 107 case ETHTOOL_LINK_EXT_STATE_AUTONEG: 108 link_ext_state_info->autoneg = 109 link_ext_state_mapping.link_ext_substate; 110 break; 111 case ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE: 112 link_ext_state_info->link_training = 113 link_ext_state_mapping.link_ext_substate; 114 break; 115 case ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH: 116 link_ext_state_info->link_logical_mismatch = 117 link_ext_state_mapping.link_ext_substate; 118 break; 119 case ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY: 120 link_ext_state_info->bad_signal_integrity = 121 link_ext_state_mapping.link_ext_substate; 122 break; 123 case ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE: 124 link_ext_state_info->cable_issue = 125 link_ext_state_mapping.link_ext_substate; 126 break; 127 default: 128 break; 129 } 130 131 link_ext_state_info->link_ext_state = link_ext_state_mapping.link_ext_state; 132 } 133 134 static int 135 mlxsw_sp_port_get_link_ext_state(struct net_device *dev, 136 struct ethtool_link_ext_state_info *link_ext_state_info) 137 { 138 struct mlxsw_sp_ethtool_link_ext_state_opcode_mapping link_ext_state_mapping; 139 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 140 char pddr_pl[MLXSW_REG_PDDR_LEN]; 141 int opcode, err, i; 142 u32 status_opcode; 143 144 if (netif_carrier_ok(dev)) 145 return -ENODATA; 146 147 mlxsw_reg_pddr_pack(pddr_pl, mlxsw_sp_port->local_port, 148 MLXSW_REG_PDDR_PAGE_SELECT_TROUBLESHOOTING_INFO); 149 150 opcode = MLXSW_REG_PDDR_TRBLSH_GROUP_OPCODE_MONITOR; 151 mlxsw_reg_pddr_trblsh_group_opcode_set(pddr_pl, opcode); 152 153 err = mlxsw_reg_query(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pddr), 154 pddr_pl); 155 if (err) 156 return err; 157 158 status_opcode = mlxsw_reg_pddr_trblsh_status_opcode_get(pddr_pl); 159 if (!status_opcode) 160 return -ENODATA; 161 162 for (i = 0; i < ARRAY_SIZE(mlxsw_sp_link_ext_state_opcode_map); i++) { 163 link_ext_state_mapping = mlxsw_sp_link_ext_state_opcode_map[i]; 164 if (link_ext_state_mapping.status_opcode == status_opcode) { 165 mlxsw_sp_port_set_link_ext_state(link_ext_state_mapping, 166 link_ext_state_info); 167 return 0; 168 } 169 } 170 171 return -ENODATA; 172 } 173 174 static void mlxsw_sp_port_get_pauseparam(struct net_device *dev, 175 struct ethtool_pauseparam *pause) 176 { 177 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 178 179 pause->rx_pause = mlxsw_sp_port->link.rx_pause; 180 pause->tx_pause = mlxsw_sp_port->link.tx_pause; 181 } 182 183 static int mlxsw_sp_port_pause_set(struct mlxsw_sp_port *mlxsw_sp_port, 184 struct ethtool_pauseparam *pause) 185 { 186 char pfcc_pl[MLXSW_REG_PFCC_LEN]; 187 188 mlxsw_reg_pfcc_pack(pfcc_pl, mlxsw_sp_port->local_port); 189 mlxsw_reg_pfcc_pprx_set(pfcc_pl, pause->rx_pause); 190 mlxsw_reg_pfcc_pptx_set(pfcc_pl, pause->tx_pause); 191 192 return mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pfcc), 193 pfcc_pl); 194 } 195 196 /* Maximum delay buffer needed in case of PAUSE frames. Similar to PFC delay, but is 197 * measured in bytes. Assumes 100m cable and does not take into account MTU. 198 */ 199 #define MLXSW_SP_PAUSE_DELAY_BYTES 19476 200 201 static int mlxsw_sp_port_set_pauseparam(struct net_device *dev, 202 struct ethtool_pauseparam *pause) 203 { 204 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 205 bool pause_en = pause->tx_pause || pause->rx_pause; 206 struct mlxsw_sp_hdroom orig_hdroom; 207 struct mlxsw_sp_hdroom hdroom; 208 int prio; 209 int err; 210 211 if (mlxsw_sp_port->dcb.pfc && mlxsw_sp_port->dcb.pfc->pfc_en) { 212 netdev_err(dev, "PFC already enabled on port\n"); 213 return -EINVAL; 214 } 215 216 if (pause->autoneg) { 217 netdev_err(dev, "PAUSE frames autonegotiation isn't supported\n"); 218 return -EINVAL; 219 } 220 221 orig_hdroom = *mlxsw_sp_port->hdroom; 222 223 hdroom = orig_hdroom; 224 if (pause_en) 225 hdroom.delay_bytes = MLXSW_SP_PAUSE_DELAY_BYTES; 226 else 227 hdroom.delay_bytes = 0; 228 229 for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++) 230 hdroom.prios.prio[prio].lossy = !pause_en; 231 232 mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom); 233 mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom); 234 235 err = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom); 236 if (err) { 237 netdev_err(dev, "Failed to configure port's headroom\n"); 238 return err; 239 } 240 241 err = mlxsw_sp_port_pause_set(mlxsw_sp_port, pause); 242 if (err) { 243 netdev_err(dev, "Failed to set PAUSE parameters\n"); 244 goto err_port_pause_configure; 245 } 246 247 mlxsw_sp_port->link.rx_pause = pause->rx_pause; 248 mlxsw_sp_port->link.tx_pause = pause->tx_pause; 249 250 return 0; 251 252 err_port_pause_configure: 253 mlxsw_sp_hdroom_configure(mlxsw_sp_port, &orig_hdroom); 254 return err; 255 } 256 257 struct mlxsw_sp_port_hw_stats { 258 char str[ETH_GSTRING_LEN]; 259 u64 (*getter)(const char *payload); 260 bool cells_bytes; 261 }; 262 263 static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_stats[] = { 264 { 265 .str = "a_frames_transmitted_ok", 266 .getter = mlxsw_reg_ppcnt_a_frames_transmitted_ok_get, 267 }, 268 { 269 .str = "a_frames_received_ok", 270 .getter = mlxsw_reg_ppcnt_a_frames_received_ok_get, 271 }, 272 { 273 .str = "a_frame_check_sequence_errors", 274 .getter = mlxsw_reg_ppcnt_a_frame_check_sequence_errors_get, 275 }, 276 { 277 .str = "a_alignment_errors", 278 .getter = mlxsw_reg_ppcnt_a_alignment_errors_get, 279 }, 280 { 281 .str = "a_octets_transmitted_ok", 282 .getter = mlxsw_reg_ppcnt_a_octets_transmitted_ok_get, 283 }, 284 { 285 .str = "a_octets_received_ok", 286 .getter = mlxsw_reg_ppcnt_a_octets_received_ok_get, 287 }, 288 { 289 .str = "a_multicast_frames_xmitted_ok", 290 .getter = mlxsw_reg_ppcnt_a_multicast_frames_xmitted_ok_get, 291 }, 292 { 293 .str = "a_broadcast_frames_xmitted_ok", 294 .getter = mlxsw_reg_ppcnt_a_broadcast_frames_xmitted_ok_get, 295 }, 296 { 297 .str = "a_multicast_frames_received_ok", 298 .getter = mlxsw_reg_ppcnt_a_multicast_frames_received_ok_get, 299 }, 300 { 301 .str = "a_broadcast_frames_received_ok", 302 .getter = mlxsw_reg_ppcnt_a_broadcast_frames_received_ok_get, 303 }, 304 { 305 .str = "a_in_range_length_errors", 306 .getter = mlxsw_reg_ppcnt_a_in_range_length_errors_get, 307 }, 308 { 309 .str = "a_out_of_range_length_field", 310 .getter = mlxsw_reg_ppcnt_a_out_of_range_length_field_get, 311 }, 312 { 313 .str = "a_frame_too_long_errors", 314 .getter = mlxsw_reg_ppcnt_a_frame_too_long_errors_get, 315 }, 316 { 317 .str = "a_symbol_error_during_carrier", 318 .getter = mlxsw_reg_ppcnt_a_symbol_error_during_carrier_get, 319 }, 320 { 321 .str = "a_mac_control_frames_transmitted", 322 .getter = mlxsw_reg_ppcnt_a_mac_control_frames_transmitted_get, 323 }, 324 { 325 .str = "a_mac_control_frames_received", 326 .getter = mlxsw_reg_ppcnt_a_mac_control_frames_received_get, 327 }, 328 { 329 .str = "a_unsupported_opcodes_received", 330 .getter = mlxsw_reg_ppcnt_a_unsupported_opcodes_received_get, 331 }, 332 { 333 .str = "a_pause_mac_ctrl_frames_received", 334 .getter = mlxsw_reg_ppcnt_a_pause_mac_ctrl_frames_received_get, 335 }, 336 { 337 .str = "a_pause_mac_ctrl_frames_xmitted", 338 .getter = mlxsw_reg_ppcnt_a_pause_mac_ctrl_frames_transmitted_get, 339 }, 340 }; 341 342 #define MLXSW_SP_PORT_HW_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_hw_stats) 343 344 static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_rfc_2863_stats[] = { 345 { 346 .str = "if_in_discards", 347 .getter = mlxsw_reg_ppcnt_if_in_discards_get, 348 }, 349 { 350 .str = "if_out_discards", 351 .getter = mlxsw_reg_ppcnt_if_out_discards_get, 352 }, 353 { 354 .str = "if_out_errors", 355 .getter = mlxsw_reg_ppcnt_if_out_errors_get, 356 }, 357 }; 358 359 #define MLXSW_SP_PORT_HW_RFC_2863_STATS_LEN \ 360 ARRAY_SIZE(mlxsw_sp_port_hw_rfc_2863_stats) 361 362 static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_rfc_2819_stats[] = { 363 { 364 .str = "ether_stats_undersize_pkts", 365 .getter = mlxsw_reg_ppcnt_ether_stats_undersize_pkts_get, 366 }, 367 { 368 .str = "ether_stats_oversize_pkts", 369 .getter = mlxsw_reg_ppcnt_ether_stats_oversize_pkts_get, 370 }, 371 { 372 .str = "ether_stats_fragments", 373 .getter = mlxsw_reg_ppcnt_ether_stats_fragments_get, 374 }, 375 { 376 .str = "ether_pkts64octets", 377 .getter = mlxsw_reg_ppcnt_ether_stats_pkts64octets_get, 378 }, 379 { 380 .str = "ether_pkts65to127octets", 381 .getter = mlxsw_reg_ppcnt_ether_stats_pkts65to127octets_get, 382 }, 383 { 384 .str = "ether_pkts128to255octets", 385 .getter = mlxsw_reg_ppcnt_ether_stats_pkts128to255octets_get, 386 }, 387 { 388 .str = "ether_pkts256to511octets", 389 .getter = mlxsw_reg_ppcnt_ether_stats_pkts256to511octets_get, 390 }, 391 { 392 .str = "ether_pkts512to1023octets", 393 .getter = mlxsw_reg_ppcnt_ether_stats_pkts512to1023octets_get, 394 }, 395 { 396 .str = "ether_pkts1024to1518octets", 397 .getter = mlxsw_reg_ppcnt_ether_stats_pkts1024to1518octets_get, 398 }, 399 { 400 .str = "ether_pkts1519to2047octets", 401 .getter = mlxsw_reg_ppcnt_ether_stats_pkts1519to2047octets_get, 402 }, 403 { 404 .str = "ether_pkts2048to4095octets", 405 .getter = mlxsw_reg_ppcnt_ether_stats_pkts2048to4095octets_get, 406 }, 407 { 408 .str = "ether_pkts4096to8191octets", 409 .getter = mlxsw_reg_ppcnt_ether_stats_pkts4096to8191octets_get, 410 }, 411 { 412 .str = "ether_pkts8192to10239octets", 413 .getter = mlxsw_reg_ppcnt_ether_stats_pkts8192to10239octets_get, 414 }, 415 }; 416 417 #define MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN \ 418 ARRAY_SIZE(mlxsw_sp_port_hw_rfc_2819_stats) 419 420 static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_rfc_3635_stats[] = { 421 { 422 .str = "dot3stats_fcs_errors", 423 .getter = mlxsw_reg_ppcnt_dot3stats_fcs_errors_get, 424 }, 425 { 426 .str = "dot3stats_symbol_errors", 427 .getter = mlxsw_reg_ppcnt_dot3stats_symbol_errors_get, 428 }, 429 { 430 .str = "dot3control_in_unknown_opcodes", 431 .getter = mlxsw_reg_ppcnt_dot3control_in_unknown_opcodes_get, 432 }, 433 { 434 .str = "dot3in_pause_frames", 435 .getter = mlxsw_reg_ppcnt_dot3in_pause_frames_get, 436 }, 437 }; 438 439 #define MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN \ 440 ARRAY_SIZE(mlxsw_sp_port_hw_rfc_3635_stats) 441 442 static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_ext_stats[] = { 443 { 444 .str = "ecn_marked", 445 .getter = mlxsw_reg_ppcnt_ecn_marked_get, 446 }, 447 }; 448 449 #define MLXSW_SP_PORT_HW_EXT_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_hw_ext_stats) 450 451 static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_discard_stats[] = { 452 { 453 .str = "discard_ingress_general", 454 .getter = mlxsw_reg_ppcnt_ingress_general_get, 455 }, 456 { 457 .str = "discard_ingress_policy_engine", 458 .getter = mlxsw_reg_ppcnt_ingress_policy_engine_get, 459 }, 460 { 461 .str = "discard_ingress_vlan_membership", 462 .getter = mlxsw_reg_ppcnt_ingress_vlan_membership_get, 463 }, 464 { 465 .str = "discard_ingress_tag_frame_type", 466 .getter = mlxsw_reg_ppcnt_ingress_tag_frame_type_get, 467 }, 468 { 469 .str = "discard_egress_vlan_membership", 470 .getter = mlxsw_reg_ppcnt_egress_vlan_membership_get, 471 }, 472 { 473 .str = "discard_loopback_filter", 474 .getter = mlxsw_reg_ppcnt_loopback_filter_get, 475 }, 476 { 477 .str = "discard_egress_general", 478 .getter = mlxsw_reg_ppcnt_egress_general_get, 479 }, 480 { 481 .str = "discard_egress_hoq", 482 .getter = mlxsw_reg_ppcnt_egress_hoq_get, 483 }, 484 { 485 .str = "discard_egress_policy_engine", 486 .getter = mlxsw_reg_ppcnt_egress_policy_engine_get, 487 }, 488 { 489 .str = "discard_ingress_tx_link_down", 490 .getter = mlxsw_reg_ppcnt_ingress_tx_link_down_get, 491 }, 492 { 493 .str = "discard_egress_stp_filter", 494 .getter = mlxsw_reg_ppcnt_egress_stp_filter_get, 495 }, 496 { 497 .str = "discard_egress_sll", 498 .getter = mlxsw_reg_ppcnt_egress_sll_get, 499 }, 500 }; 501 502 #define MLXSW_SP_PORT_HW_DISCARD_STATS_LEN \ 503 ARRAY_SIZE(mlxsw_sp_port_hw_discard_stats) 504 505 static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_prio_stats[] = { 506 { 507 .str = "rx_octets_prio", 508 .getter = mlxsw_reg_ppcnt_rx_octets_get, 509 }, 510 { 511 .str = "rx_frames_prio", 512 .getter = mlxsw_reg_ppcnt_rx_frames_get, 513 }, 514 { 515 .str = "tx_octets_prio", 516 .getter = mlxsw_reg_ppcnt_tx_octets_get, 517 }, 518 { 519 .str = "tx_frames_prio", 520 .getter = mlxsw_reg_ppcnt_tx_frames_get, 521 }, 522 { 523 .str = "rx_pause_prio", 524 .getter = mlxsw_reg_ppcnt_rx_pause_get, 525 }, 526 { 527 .str = "rx_pause_duration_prio", 528 .getter = mlxsw_reg_ppcnt_rx_pause_duration_get, 529 }, 530 { 531 .str = "tx_pause_prio", 532 .getter = mlxsw_reg_ppcnt_tx_pause_get, 533 }, 534 { 535 .str = "tx_pause_duration_prio", 536 .getter = mlxsw_reg_ppcnt_tx_pause_duration_get, 537 }, 538 }; 539 540 #define MLXSW_SP_PORT_HW_PRIO_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_hw_prio_stats) 541 542 static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_tc_stats[] = { 543 { 544 .str = "tc_transmit_queue_tc", 545 .getter = mlxsw_reg_ppcnt_tc_transmit_queue_get, 546 .cells_bytes = true, 547 }, 548 { 549 .str = "tc_no_buffer_discard_uc_tc", 550 .getter = mlxsw_reg_ppcnt_tc_no_buffer_discard_uc_get, 551 }, 552 }; 553 554 #define MLXSW_SP_PORT_HW_TC_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_hw_tc_stats) 555 556 struct mlxsw_sp_port_stats { 557 char str[ETH_GSTRING_LEN]; 558 u64 (*getter)(struct mlxsw_sp_port *mlxsw_sp_port); 559 }; 560 561 static u64 562 mlxsw_sp_port_get_transceiver_overheat_stats(struct mlxsw_sp_port *mlxsw_sp_port) 563 { 564 struct mlxsw_sp_port_mapping port_mapping = mlxsw_sp_port->mapping; 565 struct mlxsw_core *mlxsw_core = mlxsw_sp_port->mlxsw_sp->core; 566 u64 stats; 567 int err; 568 569 err = mlxsw_env_module_overheat_counter_get(mlxsw_core, 570 port_mapping.module, 571 &stats); 572 if (err) 573 return mlxsw_sp_port->module_overheat_initial_val; 574 575 return stats - mlxsw_sp_port->module_overheat_initial_val; 576 } 577 578 static struct mlxsw_sp_port_stats mlxsw_sp_port_transceiver_stats[] = { 579 { 580 .str = "transceiver_overheat", 581 .getter = mlxsw_sp_port_get_transceiver_overheat_stats, 582 }, 583 }; 584 585 #define MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_transceiver_stats) 586 587 #define MLXSW_SP_PORT_ETHTOOL_STATS_LEN (MLXSW_SP_PORT_HW_STATS_LEN + \ 588 MLXSW_SP_PORT_HW_RFC_2863_STATS_LEN + \ 589 MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN + \ 590 MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN + \ 591 MLXSW_SP_PORT_HW_EXT_STATS_LEN + \ 592 MLXSW_SP_PORT_HW_DISCARD_STATS_LEN + \ 593 (MLXSW_SP_PORT_HW_PRIO_STATS_LEN * \ 594 IEEE_8021QAZ_MAX_TCS) + \ 595 (MLXSW_SP_PORT_HW_TC_STATS_LEN * \ 596 TC_MAX_QUEUE) + \ 597 MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN) 598 599 static void mlxsw_sp_port_get_prio_strings(u8 **p, int prio) 600 { 601 int i; 602 603 for (i = 0; i < MLXSW_SP_PORT_HW_PRIO_STATS_LEN; i++) { 604 snprintf(*p, ETH_GSTRING_LEN, "%.29s_%.1d", 605 mlxsw_sp_port_hw_prio_stats[i].str, prio); 606 *p += ETH_GSTRING_LEN; 607 } 608 } 609 610 static void mlxsw_sp_port_get_tc_strings(u8 **p, int tc) 611 { 612 int i; 613 614 for (i = 0; i < MLXSW_SP_PORT_HW_TC_STATS_LEN; i++) { 615 snprintf(*p, ETH_GSTRING_LEN, "%.29s_%.1d", 616 mlxsw_sp_port_hw_tc_stats[i].str, tc); 617 *p += ETH_GSTRING_LEN; 618 } 619 } 620 621 static void mlxsw_sp_port_get_strings(struct net_device *dev, 622 u32 stringset, u8 *data) 623 { 624 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 625 u8 *p = data; 626 int i; 627 628 switch (stringset) { 629 case ETH_SS_STATS: 630 for (i = 0; i < MLXSW_SP_PORT_HW_STATS_LEN; i++) { 631 memcpy(p, mlxsw_sp_port_hw_stats[i].str, 632 ETH_GSTRING_LEN); 633 p += ETH_GSTRING_LEN; 634 } 635 636 for (i = 0; i < MLXSW_SP_PORT_HW_RFC_2863_STATS_LEN; i++) { 637 memcpy(p, mlxsw_sp_port_hw_rfc_2863_stats[i].str, 638 ETH_GSTRING_LEN); 639 p += ETH_GSTRING_LEN; 640 } 641 642 for (i = 0; i < MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN; i++) { 643 memcpy(p, mlxsw_sp_port_hw_rfc_2819_stats[i].str, 644 ETH_GSTRING_LEN); 645 p += ETH_GSTRING_LEN; 646 } 647 648 for (i = 0; i < MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN; i++) { 649 memcpy(p, mlxsw_sp_port_hw_rfc_3635_stats[i].str, 650 ETH_GSTRING_LEN); 651 p += ETH_GSTRING_LEN; 652 } 653 654 for (i = 0; i < MLXSW_SP_PORT_HW_EXT_STATS_LEN; i++) { 655 memcpy(p, mlxsw_sp_port_hw_ext_stats[i].str, 656 ETH_GSTRING_LEN); 657 p += ETH_GSTRING_LEN; 658 } 659 660 for (i = 0; i < MLXSW_SP_PORT_HW_DISCARD_STATS_LEN; i++) { 661 memcpy(p, mlxsw_sp_port_hw_discard_stats[i].str, 662 ETH_GSTRING_LEN); 663 p += ETH_GSTRING_LEN; 664 } 665 666 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) 667 mlxsw_sp_port_get_prio_strings(&p, i); 668 669 for (i = 0; i < TC_MAX_QUEUE; i++) 670 mlxsw_sp_port_get_tc_strings(&p, i); 671 672 mlxsw_sp_port->mlxsw_sp->ptp_ops->get_stats_strings(&p); 673 674 for (i = 0; i < MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN; i++) { 675 memcpy(p, mlxsw_sp_port_transceiver_stats[i].str, 676 ETH_GSTRING_LEN); 677 p += ETH_GSTRING_LEN; 678 } 679 break; 680 } 681 } 682 683 static int mlxsw_sp_port_set_phys_id(struct net_device *dev, 684 enum ethtool_phys_id_state state) 685 { 686 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 687 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 688 char mlcr_pl[MLXSW_REG_MLCR_LEN]; 689 bool active; 690 691 switch (state) { 692 case ETHTOOL_ID_ACTIVE: 693 active = true; 694 break; 695 case ETHTOOL_ID_INACTIVE: 696 active = false; 697 break; 698 default: 699 return -EOPNOTSUPP; 700 } 701 702 mlxsw_reg_mlcr_pack(mlcr_pl, mlxsw_sp_port->local_port, active); 703 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mlcr), mlcr_pl); 704 } 705 706 static int 707 mlxsw_sp_get_hw_stats_by_group(struct mlxsw_sp_port_hw_stats **p_hw_stats, 708 int *p_len, enum mlxsw_reg_ppcnt_grp grp) 709 { 710 switch (grp) { 711 case MLXSW_REG_PPCNT_IEEE_8023_CNT: 712 *p_hw_stats = mlxsw_sp_port_hw_stats; 713 *p_len = MLXSW_SP_PORT_HW_STATS_LEN; 714 break; 715 case MLXSW_REG_PPCNT_RFC_2863_CNT: 716 *p_hw_stats = mlxsw_sp_port_hw_rfc_2863_stats; 717 *p_len = MLXSW_SP_PORT_HW_RFC_2863_STATS_LEN; 718 break; 719 case MLXSW_REG_PPCNT_RFC_2819_CNT: 720 *p_hw_stats = mlxsw_sp_port_hw_rfc_2819_stats; 721 *p_len = MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN; 722 break; 723 case MLXSW_REG_PPCNT_RFC_3635_CNT: 724 *p_hw_stats = mlxsw_sp_port_hw_rfc_3635_stats; 725 *p_len = MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN; 726 break; 727 case MLXSW_REG_PPCNT_EXT_CNT: 728 *p_hw_stats = mlxsw_sp_port_hw_ext_stats; 729 *p_len = MLXSW_SP_PORT_HW_EXT_STATS_LEN; 730 break; 731 case MLXSW_REG_PPCNT_DISCARD_CNT: 732 *p_hw_stats = mlxsw_sp_port_hw_discard_stats; 733 *p_len = MLXSW_SP_PORT_HW_DISCARD_STATS_LEN; 734 break; 735 case MLXSW_REG_PPCNT_PRIO_CNT: 736 *p_hw_stats = mlxsw_sp_port_hw_prio_stats; 737 *p_len = MLXSW_SP_PORT_HW_PRIO_STATS_LEN; 738 break; 739 case MLXSW_REG_PPCNT_TC_CNT: 740 *p_hw_stats = mlxsw_sp_port_hw_tc_stats; 741 *p_len = MLXSW_SP_PORT_HW_TC_STATS_LEN; 742 break; 743 default: 744 WARN_ON(1); 745 return -EOPNOTSUPP; 746 } 747 return 0; 748 } 749 750 static void __mlxsw_sp_port_get_stats(struct net_device *dev, 751 enum mlxsw_reg_ppcnt_grp grp, int prio, 752 u64 *data, int data_index) 753 { 754 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 755 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 756 struct mlxsw_sp_port_hw_stats *hw_stats; 757 char ppcnt_pl[MLXSW_REG_PPCNT_LEN]; 758 int i, len; 759 int err; 760 761 err = mlxsw_sp_get_hw_stats_by_group(&hw_stats, &len, grp); 762 if (err) 763 return; 764 mlxsw_sp_port_get_stats_raw(dev, grp, prio, ppcnt_pl); 765 for (i = 0; i < len; i++) { 766 data[data_index + i] = hw_stats[i].getter(ppcnt_pl); 767 if (!hw_stats[i].cells_bytes) 768 continue; 769 data[data_index + i] = mlxsw_sp_cells_bytes(mlxsw_sp, 770 data[data_index + i]); 771 } 772 } 773 774 static void __mlxsw_sp_port_get_env_stats(struct net_device *dev, u64 *data, int data_index, 775 struct mlxsw_sp_port_stats *port_stats, 776 int len) 777 { 778 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 779 int i; 780 781 for (i = 0; i < len; i++) 782 data[data_index + i] = port_stats[i].getter(mlxsw_sp_port); 783 } 784 785 static void mlxsw_sp_port_get_stats(struct net_device *dev, 786 struct ethtool_stats *stats, u64 *data) 787 { 788 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 789 int i, data_index = 0; 790 791 /* IEEE 802.3 Counters */ 792 __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT, 0, 793 data, data_index); 794 data_index = MLXSW_SP_PORT_HW_STATS_LEN; 795 796 /* RFC 2863 Counters */ 797 __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_RFC_2863_CNT, 0, 798 data, data_index); 799 data_index += MLXSW_SP_PORT_HW_RFC_2863_STATS_LEN; 800 801 /* RFC 2819 Counters */ 802 __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_RFC_2819_CNT, 0, 803 data, data_index); 804 data_index += MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN; 805 806 /* RFC 3635 Counters */ 807 __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_RFC_3635_CNT, 0, 808 data, data_index); 809 data_index += MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN; 810 811 /* Extended Counters */ 812 __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_EXT_CNT, 0, 813 data, data_index); 814 data_index += MLXSW_SP_PORT_HW_EXT_STATS_LEN; 815 816 /* Discard Counters */ 817 __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_DISCARD_CNT, 0, 818 data, data_index); 819 data_index += MLXSW_SP_PORT_HW_DISCARD_STATS_LEN; 820 821 /* Per-Priority Counters */ 822 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 823 __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_PRIO_CNT, i, 824 data, data_index); 825 data_index += MLXSW_SP_PORT_HW_PRIO_STATS_LEN; 826 } 827 828 /* Per-TC Counters */ 829 for (i = 0; i < TC_MAX_QUEUE; i++) { 830 __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_TC_CNT, i, 831 data, data_index); 832 data_index += MLXSW_SP_PORT_HW_TC_STATS_LEN; 833 } 834 835 /* PTP counters */ 836 mlxsw_sp_port->mlxsw_sp->ptp_ops->get_stats(mlxsw_sp_port, 837 data, data_index); 838 data_index += mlxsw_sp_port->mlxsw_sp->ptp_ops->get_stats_count(); 839 840 /* Transceiver counters */ 841 __mlxsw_sp_port_get_env_stats(dev, data, data_index, mlxsw_sp_port_transceiver_stats, 842 MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN); 843 data_index += MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN; 844 } 845 846 static int mlxsw_sp_port_get_sset_count(struct net_device *dev, int sset) 847 { 848 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 849 850 switch (sset) { 851 case ETH_SS_STATS: 852 return MLXSW_SP_PORT_ETHTOOL_STATS_LEN + 853 mlxsw_sp_port->mlxsw_sp->ptp_ops->get_stats_count(); 854 default: 855 return -EOPNOTSUPP; 856 } 857 } 858 859 static void 860 mlxsw_sp_port_get_link_supported(struct mlxsw_sp *mlxsw_sp, u32 eth_proto_cap, 861 struct ethtool_link_ksettings *cmd) 862 { 863 const struct mlxsw_sp_port_type_speed_ops *ops; 864 865 ops = mlxsw_sp->port_type_speed_ops; 866 867 ethtool_link_ksettings_add_link_mode(cmd, supported, Asym_Pause); 868 ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg); 869 ethtool_link_ksettings_add_link_mode(cmd, supported, Pause); 870 871 ops->from_ptys_supported_port(mlxsw_sp, eth_proto_cap, cmd); 872 ops->from_ptys_link(mlxsw_sp, eth_proto_cap, 873 cmd->link_modes.supported); 874 } 875 876 static void 877 mlxsw_sp_port_get_link_advertise(struct mlxsw_sp *mlxsw_sp, 878 u32 eth_proto_admin, bool autoneg, 879 struct ethtool_link_ksettings *cmd) 880 { 881 const struct mlxsw_sp_port_type_speed_ops *ops; 882 883 ops = mlxsw_sp->port_type_speed_ops; 884 885 if (!autoneg) 886 return; 887 888 ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg); 889 ops->from_ptys_link(mlxsw_sp, eth_proto_admin, 890 cmd->link_modes.advertising); 891 } 892 893 static u8 894 mlxsw_sp_port_connector_port(enum mlxsw_reg_ptys_connector_type connector_type) 895 { 896 switch (connector_type) { 897 case MLXSW_REG_PTYS_CONNECTOR_TYPE_UNKNOWN_OR_NO_CONNECTOR: 898 return PORT_OTHER; 899 case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_NONE: 900 return PORT_NONE; 901 case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_TP: 902 return PORT_TP; 903 case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_AUI: 904 return PORT_AUI; 905 case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_BNC: 906 return PORT_BNC; 907 case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_MII: 908 return PORT_MII; 909 case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_FIBRE: 910 return PORT_FIBRE; 911 case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_DA: 912 return PORT_DA; 913 case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_OTHER: 914 return PORT_OTHER; 915 default: 916 WARN_ON_ONCE(1); 917 return PORT_OTHER; 918 } 919 } 920 921 static int mlxsw_sp_port_ptys_query(struct mlxsw_sp_port *mlxsw_sp_port, 922 u32 *p_eth_proto_cap, u32 *p_eth_proto_admin, 923 u32 *p_eth_proto_oper, u8 *p_connector_type) 924 { 925 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 926 const struct mlxsw_sp_port_type_speed_ops *ops; 927 char ptys_pl[MLXSW_REG_PTYS_LEN]; 928 int err; 929 930 ops = mlxsw_sp->port_type_speed_ops; 931 932 ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port, 0, false); 933 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl); 934 if (err) 935 return err; 936 937 ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, p_eth_proto_cap, p_eth_proto_admin, 938 p_eth_proto_oper); 939 if (p_connector_type) 940 *p_connector_type = mlxsw_reg_ptys_connector_type_get(ptys_pl); 941 return 0; 942 } 943 944 static int mlxsw_sp_port_get_link_ksettings(struct net_device *dev, 945 struct ethtool_link_ksettings *cmd) 946 { 947 u32 eth_proto_cap, eth_proto_admin, eth_proto_oper; 948 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 949 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 950 const struct mlxsw_sp_port_type_speed_ops *ops; 951 u8 connector_type; 952 bool autoneg; 953 int err; 954 955 err = mlxsw_sp_port_ptys_query(mlxsw_sp_port, ð_proto_cap, ð_proto_admin, 956 ð_proto_oper, &connector_type); 957 if (err) 958 return err; 959 960 ops = mlxsw_sp->port_type_speed_ops; 961 autoneg = mlxsw_sp_port->link.autoneg; 962 963 mlxsw_sp_port_get_link_supported(mlxsw_sp, eth_proto_cap, cmd); 964 965 mlxsw_sp_port_get_link_advertise(mlxsw_sp, eth_proto_admin, autoneg, cmd); 966 967 cmd->base.autoneg = autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE; 968 cmd->base.port = mlxsw_sp_port_connector_port(connector_type); 969 ops->from_ptys_link_mode(mlxsw_sp, netif_carrier_ok(dev), 970 eth_proto_oper, cmd); 971 972 return 0; 973 } 974 975 static int 976 mlxsw_sp_port_set_link_ksettings(struct net_device *dev, 977 const struct ethtool_link_ksettings *cmd) 978 { 979 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 980 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 981 const struct mlxsw_sp_port_type_speed_ops *ops; 982 char ptys_pl[MLXSW_REG_PTYS_LEN]; 983 u32 eth_proto_cap, eth_proto_new; 984 bool autoneg; 985 int err; 986 987 ops = mlxsw_sp->port_type_speed_ops; 988 989 ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port, 990 0, false); 991 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl); 992 if (err) 993 return err; 994 ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, ð_proto_cap, NULL, NULL); 995 996 autoneg = cmd->base.autoneg == AUTONEG_ENABLE; 997 eth_proto_new = autoneg ? 998 ops->to_ptys_advert_link(mlxsw_sp, cmd) : 999 ops->to_ptys_speed_lanes(mlxsw_sp, mlxsw_sp_port->mapping.width, 1000 cmd); 1001 1002 eth_proto_new = eth_proto_new & eth_proto_cap; 1003 if (!eth_proto_new) { 1004 netdev_err(dev, "No supported speed or lanes requested\n"); 1005 return -EINVAL; 1006 } 1007 1008 ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port, 1009 eth_proto_new, autoneg); 1010 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl); 1011 if (err) 1012 return err; 1013 1014 mlxsw_sp_port->link.autoneg = autoneg; 1015 1016 if (!netif_running(dev)) 1017 return 0; 1018 1019 mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false); 1020 mlxsw_sp_port_admin_status_set(mlxsw_sp_port, true); 1021 1022 return 0; 1023 } 1024 1025 static int mlxsw_sp_get_module_info(struct net_device *netdev, 1026 struct ethtool_modinfo *modinfo) 1027 { 1028 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(netdev); 1029 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 1030 int err; 1031 1032 err = mlxsw_env_get_module_info(mlxsw_sp->core, 1033 mlxsw_sp_port->mapping.module, 1034 modinfo); 1035 1036 return err; 1037 } 1038 1039 static int mlxsw_sp_get_module_eeprom(struct net_device *netdev, 1040 struct ethtool_eeprom *ee, u8 *data) 1041 { 1042 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(netdev); 1043 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 1044 int err; 1045 1046 err = mlxsw_env_get_module_eeprom(netdev, mlxsw_sp->core, 1047 mlxsw_sp_port->mapping.module, ee, 1048 data); 1049 1050 return err; 1051 } 1052 1053 static int 1054 mlxsw_sp_get_module_eeprom_by_page(struct net_device *dev, 1055 const struct ethtool_module_eeprom *page, 1056 struct netlink_ext_ack *extack) 1057 { 1058 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 1059 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 1060 u8 module = mlxsw_sp_port->mapping.module; 1061 1062 return mlxsw_env_get_module_eeprom_by_page(mlxsw_sp->core, module, page, 1063 extack); 1064 } 1065 1066 static int 1067 mlxsw_sp_get_ts_info(struct net_device *netdev, struct ethtool_ts_info *info) 1068 { 1069 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(netdev); 1070 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 1071 1072 return mlxsw_sp->ptp_ops->get_ts_info(mlxsw_sp, info); 1073 } 1074 1075 static void 1076 mlxsw_sp_get_eth_phy_stats(struct net_device *dev, 1077 struct ethtool_eth_phy_stats *phy_stats) 1078 { 1079 char ppcnt_pl[MLXSW_REG_PPCNT_LEN]; 1080 1081 if (mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT, 1082 0, ppcnt_pl)) 1083 return; 1084 1085 phy_stats->SymbolErrorDuringCarrier = 1086 mlxsw_reg_ppcnt_a_symbol_error_during_carrier_get(ppcnt_pl); 1087 } 1088 1089 static void 1090 mlxsw_sp_get_eth_mac_stats(struct net_device *dev, 1091 struct ethtool_eth_mac_stats *mac_stats) 1092 { 1093 char ppcnt_pl[MLXSW_REG_PPCNT_LEN]; 1094 1095 if (mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT, 1096 0, ppcnt_pl)) 1097 return; 1098 1099 mac_stats->FramesTransmittedOK = 1100 mlxsw_reg_ppcnt_a_frames_transmitted_ok_get(ppcnt_pl); 1101 mac_stats->FramesReceivedOK = 1102 mlxsw_reg_ppcnt_a_frames_received_ok_get(ppcnt_pl); 1103 mac_stats->FrameCheckSequenceErrors = 1104 mlxsw_reg_ppcnt_a_frame_check_sequence_errors_get(ppcnt_pl); 1105 mac_stats->AlignmentErrors = 1106 mlxsw_reg_ppcnt_a_alignment_errors_get(ppcnt_pl); 1107 mac_stats->OctetsTransmittedOK = 1108 mlxsw_reg_ppcnt_a_octets_transmitted_ok_get(ppcnt_pl); 1109 mac_stats->OctetsReceivedOK = 1110 mlxsw_reg_ppcnt_a_octets_received_ok_get(ppcnt_pl); 1111 mac_stats->MulticastFramesXmittedOK = 1112 mlxsw_reg_ppcnt_a_multicast_frames_xmitted_ok_get(ppcnt_pl); 1113 mac_stats->BroadcastFramesXmittedOK = 1114 mlxsw_reg_ppcnt_a_broadcast_frames_xmitted_ok_get(ppcnt_pl); 1115 mac_stats->MulticastFramesReceivedOK = 1116 mlxsw_reg_ppcnt_a_multicast_frames_received_ok_get(ppcnt_pl); 1117 mac_stats->BroadcastFramesReceivedOK = 1118 mlxsw_reg_ppcnt_a_broadcast_frames_received_ok_get(ppcnt_pl); 1119 mac_stats->InRangeLengthErrors = 1120 mlxsw_reg_ppcnt_a_in_range_length_errors_get(ppcnt_pl); 1121 mac_stats->OutOfRangeLengthField = 1122 mlxsw_reg_ppcnt_a_out_of_range_length_field_get(ppcnt_pl); 1123 mac_stats->FrameTooLongErrors = 1124 mlxsw_reg_ppcnt_a_frame_too_long_errors_get(ppcnt_pl); 1125 } 1126 1127 static void 1128 mlxsw_sp_get_eth_ctrl_stats(struct net_device *dev, 1129 struct ethtool_eth_ctrl_stats *ctrl_stats) 1130 { 1131 char ppcnt_pl[MLXSW_REG_PPCNT_LEN]; 1132 1133 if (mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT, 1134 0, ppcnt_pl)) 1135 return; 1136 1137 ctrl_stats->MACControlFramesTransmitted = 1138 mlxsw_reg_ppcnt_a_mac_control_frames_transmitted_get(ppcnt_pl); 1139 ctrl_stats->MACControlFramesReceived = 1140 mlxsw_reg_ppcnt_a_mac_control_frames_received_get(ppcnt_pl); 1141 ctrl_stats->UnsupportedOpcodesReceived = 1142 mlxsw_reg_ppcnt_a_unsupported_opcodes_received_get(ppcnt_pl); 1143 } 1144 1145 static const struct ethtool_rmon_hist_range mlxsw_rmon_ranges[] = { 1146 { 0, 64 }, 1147 { 65, 127 }, 1148 { 128, 255 }, 1149 { 256, 511 }, 1150 { 512, 1023 }, 1151 { 1024, 1518 }, 1152 { 1519, 2047 }, 1153 { 2048, 4095 }, 1154 { 4096, 8191 }, 1155 { 8192, 10239 }, 1156 {} 1157 }; 1158 1159 static void 1160 mlxsw_sp_get_rmon_stats(struct net_device *dev, 1161 struct ethtool_rmon_stats *rmon, 1162 const struct ethtool_rmon_hist_range **ranges) 1163 { 1164 char ppcnt_pl[MLXSW_REG_PPCNT_LEN]; 1165 1166 if (mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_RFC_2819_CNT, 1167 0, ppcnt_pl)) 1168 return; 1169 1170 rmon->undersize_pkts = 1171 mlxsw_reg_ppcnt_ether_stats_undersize_pkts_get(ppcnt_pl); 1172 rmon->oversize_pkts = 1173 mlxsw_reg_ppcnt_ether_stats_oversize_pkts_get(ppcnt_pl); 1174 rmon->fragments = 1175 mlxsw_reg_ppcnt_ether_stats_fragments_get(ppcnt_pl); 1176 1177 rmon->hist[0] = mlxsw_reg_ppcnt_ether_stats_pkts64octets_get(ppcnt_pl); 1178 rmon->hist[1] = 1179 mlxsw_reg_ppcnt_ether_stats_pkts65to127octets_get(ppcnt_pl); 1180 rmon->hist[2] = 1181 mlxsw_reg_ppcnt_ether_stats_pkts128to255octets_get(ppcnt_pl); 1182 rmon->hist[3] = 1183 mlxsw_reg_ppcnt_ether_stats_pkts256to511octets_get(ppcnt_pl); 1184 rmon->hist[4] = 1185 mlxsw_reg_ppcnt_ether_stats_pkts512to1023octets_get(ppcnt_pl); 1186 rmon->hist[5] = 1187 mlxsw_reg_ppcnt_ether_stats_pkts1024to1518octets_get(ppcnt_pl); 1188 rmon->hist[6] = 1189 mlxsw_reg_ppcnt_ether_stats_pkts1519to2047octets_get(ppcnt_pl); 1190 rmon->hist[7] = 1191 mlxsw_reg_ppcnt_ether_stats_pkts2048to4095octets_get(ppcnt_pl); 1192 rmon->hist[8] = 1193 mlxsw_reg_ppcnt_ether_stats_pkts4096to8191octets_get(ppcnt_pl); 1194 rmon->hist[9] = 1195 mlxsw_reg_ppcnt_ether_stats_pkts8192to10239octets_get(ppcnt_pl); 1196 1197 *ranges = mlxsw_rmon_ranges; 1198 } 1199 1200 const struct ethtool_ops mlxsw_sp_port_ethtool_ops = { 1201 .cap_link_lanes_supported = true, 1202 .get_drvinfo = mlxsw_sp_port_get_drvinfo, 1203 .get_link = ethtool_op_get_link, 1204 .get_link_ext_state = mlxsw_sp_port_get_link_ext_state, 1205 .get_pauseparam = mlxsw_sp_port_get_pauseparam, 1206 .set_pauseparam = mlxsw_sp_port_set_pauseparam, 1207 .get_strings = mlxsw_sp_port_get_strings, 1208 .set_phys_id = mlxsw_sp_port_set_phys_id, 1209 .get_ethtool_stats = mlxsw_sp_port_get_stats, 1210 .get_sset_count = mlxsw_sp_port_get_sset_count, 1211 .get_link_ksettings = mlxsw_sp_port_get_link_ksettings, 1212 .set_link_ksettings = mlxsw_sp_port_set_link_ksettings, 1213 .get_module_info = mlxsw_sp_get_module_info, 1214 .get_module_eeprom = mlxsw_sp_get_module_eeprom, 1215 .get_module_eeprom_by_page = mlxsw_sp_get_module_eeprom_by_page, 1216 .get_ts_info = mlxsw_sp_get_ts_info, 1217 .get_eth_phy_stats = mlxsw_sp_get_eth_phy_stats, 1218 .get_eth_mac_stats = mlxsw_sp_get_eth_mac_stats, 1219 .get_eth_ctrl_stats = mlxsw_sp_get_eth_ctrl_stats, 1220 .get_rmon_stats = mlxsw_sp_get_rmon_stats, 1221 }; 1222 1223 struct mlxsw_sp1_port_link_mode { 1224 enum ethtool_link_mode_bit_indices mask_ethtool; 1225 u32 mask; 1226 u32 speed; 1227 }; 1228 1229 static const struct mlxsw_sp1_port_link_mode mlxsw_sp1_port_link_mode[] = { 1230 { 1231 .mask = MLXSW_REG_PTYS_ETH_SPEED_SGMII | 1232 MLXSW_REG_PTYS_ETH_SPEED_1000BASE_KX, 1233 .mask_ethtool = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, 1234 .speed = SPEED_1000, 1235 }, 1236 { 1237 .mask = MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CX4 | 1238 MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4, 1239 .mask_ethtool = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, 1240 .speed = SPEED_10000, 1241 }, 1242 { 1243 .mask = MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR | 1244 MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR | 1245 MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR | 1246 MLXSW_REG_PTYS_ETH_SPEED_10GBASE_ER_LR, 1247 .mask_ethtool = ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, 1248 .speed = SPEED_10000, 1249 }, 1250 { 1251 .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4, 1252 .mask_ethtool = ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, 1253 .speed = SPEED_40000, 1254 }, 1255 { 1256 .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4, 1257 .mask_ethtool = ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, 1258 .speed = SPEED_40000, 1259 }, 1260 { 1261 .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4, 1262 .mask_ethtool = ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, 1263 .speed = SPEED_40000, 1264 }, 1265 { 1266 .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_LR4_ER4, 1267 .mask_ethtool = ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, 1268 .speed = SPEED_40000, 1269 }, 1270 { 1271 .mask = MLXSW_REG_PTYS_ETH_SPEED_25GBASE_CR, 1272 .mask_ethtool = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, 1273 .speed = SPEED_25000, 1274 }, 1275 { 1276 .mask = MLXSW_REG_PTYS_ETH_SPEED_25GBASE_KR, 1277 .mask_ethtool = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, 1278 .speed = SPEED_25000, 1279 }, 1280 { 1281 .mask = MLXSW_REG_PTYS_ETH_SPEED_25GBASE_SR, 1282 .mask_ethtool = ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, 1283 .speed = SPEED_25000, 1284 }, 1285 { 1286 .mask = MLXSW_REG_PTYS_ETH_SPEED_50GBASE_CR2, 1287 .mask_ethtool = ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, 1288 .speed = SPEED_50000, 1289 }, 1290 { 1291 .mask = MLXSW_REG_PTYS_ETH_SPEED_50GBASE_KR2, 1292 .mask_ethtool = ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, 1293 .speed = SPEED_50000, 1294 }, 1295 { 1296 .mask = MLXSW_REG_PTYS_ETH_SPEED_50GBASE_SR2, 1297 .mask_ethtool = ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, 1298 .speed = SPEED_50000, 1299 }, 1300 { 1301 .mask = MLXSW_REG_PTYS_ETH_SPEED_100GBASE_CR4, 1302 .mask_ethtool = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, 1303 .speed = SPEED_100000, 1304 }, 1305 { 1306 .mask = MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4, 1307 .mask_ethtool = ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, 1308 .speed = SPEED_100000, 1309 }, 1310 { 1311 .mask = MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4, 1312 .mask_ethtool = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, 1313 .speed = SPEED_100000, 1314 }, 1315 { 1316 .mask = MLXSW_REG_PTYS_ETH_SPEED_100GBASE_LR4_ER4, 1317 .mask_ethtool = ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT, 1318 .speed = SPEED_100000, 1319 }, 1320 }; 1321 1322 #define MLXSW_SP1_PORT_LINK_MODE_LEN ARRAY_SIZE(mlxsw_sp1_port_link_mode) 1323 1324 static void 1325 mlxsw_sp1_from_ptys_supported_port(struct mlxsw_sp *mlxsw_sp, 1326 u32 ptys_eth_proto, 1327 struct ethtool_link_ksettings *cmd) 1328 { 1329 if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR | 1330 MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR | 1331 MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4 | 1332 MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4 | 1333 MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4 | 1334 MLXSW_REG_PTYS_ETH_SPEED_SGMII)) 1335 ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); 1336 1337 if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR | 1338 MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4 | 1339 MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4 | 1340 MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4 | 1341 MLXSW_REG_PTYS_ETH_SPEED_1000BASE_KX)) 1342 ethtool_link_ksettings_add_link_mode(cmd, supported, Backplane); 1343 } 1344 1345 static void 1346 mlxsw_sp1_from_ptys_link(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto, 1347 unsigned long *mode) 1348 { 1349 int i; 1350 1351 for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) { 1352 if (ptys_eth_proto & mlxsw_sp1_port_link_mode[i].mask) 1353 __set_bit(mlxsw_sp1_port_link_mode[i].mask_ethtool, 1354 mode); 1355 } 1356 } 1357 1358 static u32 1359 mlxsw_sp1_from_ptys_speed(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto) 1360 { 1361 int i; 1362 1363 for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) { 1364 if (ptys_eth_proto & mlxsw_sp1_port_link_mode[i].mask) 1365 return mlxsw_sp1_port_link_mode[i].speed; 1366 } 1367 1368 return SPEED_UNKNOWN; 1369 } 1370 1371 static void 1372 mlxsw_sp1_from_ptys_link_mode(struct mlxsw_sp *mlxsw_sp, bool carrier_ok, 1373 u32 ptys_eth_proto, 1374 struct ethtool_link_ksettings *cmd) 1375 { 1376 struct mlxsw_sp1_port_link_mode link; 1377 int i; 1378 1379 cmd->base.speed = SPEED_UNKNOWN; 1380 cmd->base.duplex = DUPLEX_UNKNOWN; 1381 cmd->lanes = 0; 1382 1383 if (!carrier_ok) 1384 return; 1385 1386 for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) { 1387 if (ptys_eth_proto & mlxsw_sp1_port_link_mode[i].mask) { 1388 link = mlxsw_sp1_port_link_mode[i]; 1389 ethtool_params_from_link_mode(cmd, 1390 link.mask_ethtool); 1391 } 1392 } 1393 } 1394 1395 static int mlxsw_sp1_ptys_max_speed(struct mlxsw_sp_port *mlxsw_sp_port, u32 *p_max_speed) 1396 { 1397 u32 eth_proto_cap; 1398 u32 max_speed = 0; 1399 int err; 1400 int i; 1401 1402 err = mlxsw_sp_port_ptys_query(mlxsw_sp_port, ð_proto_cap, NULL, NULL, NULL); 1403 if (err) 1404 return err; 1405 1406 for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) { 1407 if ((eth_proto_cap & mlxsw_sp1_port_link_mode[i].mask) && 1408 mlxsw_sp1_port_link_mode[i].speed > max_speed) 1409 max_speed = mlxsw_sp1_port_link_mode[i].speed; 1410 } 1411 1412 *p_max_speed = max_speed; 1413 return 0; 1414 } 1415 1416 static u32 1417 mlxsw_sp1_to_ptys_advert_link(struct mlxsw_sp *mlxsw_sp, 1418 const struct ethtool_link_ksettings *cmd) 1419 { 1420 u32 ptys_proto = 0; 1421 int i; 1422 1423 for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) { 1424 if (test_bit(mlxsw_sp1_port_link_mode[i].mask_ethtool, 1425 cmd->link_modes.advertising)) 1426 ptys_proto |= mlxsw_sp1_port_link_mode[i].mask; 1427 } 1428 return ptys_proto; 1429 } 1430 1431 static u32 mlxsw_sp1_to_ptys_speed_lanes(struct mlxsw_sp *mlxsw_sp, u8 width, 1432 const struct ethtool_link_ksettings *cmd) 1433 { 1434 u32 ptys_proto = 0; 1435 int i; 1436 1437 if (cmd->lanes > width) 1438 return ptys_proto; 1439 1440 for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) { 1441 if (cmd->base.speed == mlxsw_sp1_port_link_mode[i].speed) 1442 ptys_proto |= mlxsw_sp1_port_link_mode[i].mask; 1443 } 1444 return ptys_proto; 1445 } 1446 1447 static void 1448 mlxsw_sp1_reg_ptys_eth_pack(struct mlxsw_sp *mlxsw_sp, char *payload, 1449 u8 local_port, u32 proto_admin, bool autoneg) 1450 { 1451 mlxsw_reg_ptys_eth_pack(payload, local_port, proto_admin, autoneg); 1452 } 1453 1454 static void 1455 mlxsw_sp1_reg_ptys_eth_unpack(struct mlxsw_sp *mlxsw_sp, char *payload, 1456 u32 *p_eth_proto_cap, u32 *p_eth_proto_admin, 1457 u32 *p_eth_proto_oper) 1458 { 1459 mlxsw_reg_ptys_eth_unpack(payload, p_eth_proto_cap, p_eth_proto_admin, 1460 p_eth_proto_oper); 1461 } 1462 1463 static u32 mlxsw_sp1_ptys_proto_cap_masked_get(u32 eth_proto_cap) 1464 { 1465 u32 ptys_proto_cap_masked = 0; 1466 int i; 1467 1468 for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) { 1469 if (mlxsw_sp1_port_link_mode[i].mask & eth_proto_cap) 1470 ptys_proto_cap_masked |= 1471 mlxsw_sp1_port_link_mode[i].mask; 1472 } 1473 1474 return ptys_proto_cap_masked; 1475 } 1476 1477 const struct mlxsw_sp_port_type_speed_ops mlxsw_sp1_port_type_speed_ops = { 1478 .from_ptys_supported_port = mlxsw_sp1_from_ptys_supported_port, 1479 .from_ptys_link = mlxsw_sp1_from_ptys_link, 1480 .from_ptys_speed = mlxsw_sp1_from_ptys_speed, 1481 .from_ptys_link_mode = mlxsw_sp1_from_ptys_link_mode, 1482 .ptys_max_speed = mlxsw_sp1_ptys_max_speed, 1483 .to_ptys_advert_link = mlxsw_sp1_to_ptys_advert_link, 1484 .to_ptys_speed_lanes = mlxsw_sp1_to_ptys_speed_lanes, 1485 .reg_ptys_eth_pack = mlxsw_sp1_reg_ptys_eth_pack, 1486 .reg_ptys_eth_unpack = mlxsw_sp1_reg_ptys_eth_unpack, 1487 .ptys_proto_cap_masked_get = mlxsw_sp1_ptys_proto_cap_masked_get, 1488 }; 1489 1490 static const enum ethtool_link_mode_bit_indices 1491 mlxsw_sp2_mask_ethtool_sgmii_100m[] = { 1492 ETHTOOL_LINK_MODE_100baseT_Full_BIT, 1493 }; 1494 1495 #define MLXSW_SP2_MASK_ETHTOOL_SGMII_100M_LEN \ 1496 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_sgmii_100m) 1497 1498 static const enum ethtool_link_mode_bit_indices 1499 mlxsw_sp2_mask_ethtool_1000base_x_sgmii[] = { 1500 ETHTOOL_LINK_MODE_1000baseT_Full_BIT, 1501 ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, 1502 }; 1503 1504 #define MLXSW_SP2_MASK_ETHTOOL_1000BASE_X_SGMII_LEN \ 1505 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_1000base_x_sgmii) 1506 1507 static const enum ethtool_link_mode_bit_indices 1508 mlxsw_sp2_mask_ethtool_5gbase_r[] = { 1509 ETHTOOL_LINK_MODE_5000baseT_Full_BIT, 1510 }; 1511 1512 #define MLXSW_SP2_MASK_ETHTOOL_5GBASE_R_LEN \ 1513 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_5gbase_r) 1514 1515 static const enum ethtool_link_mode_bit_indices 1516 mlxsw_sp2_mask_ethtool_xfi_xaui_1_10g[] = { 1517 ETHTOOL_LINK_MODE_10000baseT_Full_BIT, 1518 ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, 1519 ETHTOOL_LINK_MODE_10000baseR_FEC_BIT, 1520 ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, 1521 ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, 1522 ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, 1523 ETHTOOL_LINK_MODE_10000baseER_Full_BIT, 1524 }; 1525 1526 #define MLXSW_SP2_MASK_ETHTOOL_XFI_XAUI_1_10G_LEN \ 1527 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_xfi_xaui_1_10g) 1528 1529 static const enum ethtool_link_mode_bit_indices 1530 mlxsw_sp2_mask_ethtool_xlaui_4_xlppi_4_40g[] = { 1531 ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, 1532 ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, 1533 ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, 1534 ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, 1535 }; 1536 1537 #define MLXSW_SP2_MASK_ETHTOOL_XLAUI_4_XLPPI_4_40G_LEN \ 1538 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_xlaui_4_xlppi_4_40g) 1539 1540 static const enum ethtool_link_mode_bit_indices 1541 mlxsw_sp2_mask_ethtool_25gaui_1_25gbase_cr_kr[] = { 1542 ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, 1543 ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, 1544 ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, 1545 }; 1546 1547 #define MLXSW_SP2_MASK_ETHTOOL_25GAUI_1_25GBASE_CR_KR_LEN \ 1548 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_25gaui_1_25gbase_cr_kr) 1549 1550 static const enum ethtool_link_mode_bit_indices 1551 mlxsw_sp2_mask_ethtool_50gaui_2_laui_2_50gbase_cr2_kr2[] = { 1552 ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, 1553 ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, 1554 ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, 1555 }; 1556 1557 #define MLXSW_SP2_MASK_ETHTOOL_50GAUI_2_LAUI_2_50GBASE_CR2_KR2_LEN \ 1558 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_50gaui_2_laui_2_50gbase_cr2_kr2) 1559 1560 static const enum ethtool_link_mode_bit_indices 1561 mlxsw_sp2_mask_ethtool_50gaui_1_laui_1_50gbase_cr_kr[] = { 1562 ETHTOOL_LINK_MODE_50000baseKR_Full_BIT, 1563 ETHTOOL_LINK_MODE_50000baseSR_Full_BIT, 1564 ETHTOOL_LINK_MODE_50000baseCR_Full_BIT, 1565 ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT, 1566 ETHTOOL_LINK_MODE_50000baseDR_Full_BIT, 1567 }; 1568 1569 #define MLXSW_SP2_MASK_ETHTOOL_50GAUI_1_LAUI_1_50GBASE_CR_KR_LEN \ 1570 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_50gaui_1_laui_1_50gbase_cr_kr) 1571 1572 static const enum ethtool_link_mode_bit_indices 1573 mlxsw_sp2_mask_ethtool_caui_4_100gbase_cr4_kr4[] = { 1574 ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, 1575 ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, 1576 ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, 1577 ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT, 1578 }; 1579 1580 #define MLXSW_SP2_MASK_ETHTOOL_CAUI_4_100GBASE_CR4_KR4_LEN \ 1581 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_caui_4_100gbase_cr4_kr4) 1582 1583 static const enum ethtool_link_mode_bit_indices 1584 mlxsw_sp2_mask_ethtool_100gaui_2_100gbase_cr2_kr2[] = { 1585 ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT, 1586 ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT, 1587 ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT, 1588 ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT, 1589 ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT, 1590 }; 1591 1592 #define MLXSW_SP2_MASK_ETHTOOL_100GAUI_2_100GBASE_CR2_KR2_LEN \ 1593 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_100gaui_2_100gbase_cr2_kr2) 1594 1595 static const enum ethtool_link_mode_bit_indices 1596 mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4[] = { 1597 ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT, 1598 ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT, 1599 ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT, 1600 ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT, 1601 ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT, 1602 }; 1603 1604 #define MLXSW_SP2_MASK_ETHTOOL_200GAUI_4_200GBASE_CR4_KR4_LEN \ 1605 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4) 1606 1607 static const enum ethtool_link_mode_bit_indices 1608 mlxsw_sp2_mask_ethtool_400gaui_8[] = { 1609 ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT, 1610 ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT, 1611 ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT, 1612 ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT, 1613 ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT, 1614 }; 1615 1616 #define MLXSW_SP2_MASK_ETHTOOL_400GAUI_8_LEN \ 1617 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_400gaui_8) 1618 1619 #define MLXSW_SP_PORT_MASK_WIDTH_1X BIT(0) 1620 #define MLXSW_SP_PORT_MASK_WIDTH_2X BIT(1) 1621 #define MLXSW_SP_PORT_MASK_WIDTH_4X BIT(2) 1622 #define MLXSW_SP_PORT_MASK_WIDTH_8X BIT(3) 1623 1624 static u8 mlxsw_sp_port_mask_width_get(u8 width) 1625 { 1626 switch (width) { 1627 case 1: 1628 return MLXSW_SP_PORT_MASK_WIDTH_1X; 1629 case 2: 1630 return MLXSW_SP_PORT_MASK_WIDTH_2X; 1631 case 4: 1632 return MLXSW_SP_PORT_MASK_WIDTH_4X; 1633 case 8: 1634 return MLXSW_SP_PORT_MASK_WIDTH_8X; 1635 default: 1636 WARN_ON_ONCE(1); 1637 return 0; 1638 } 1639 } 1640 1641 struct mlxsw_sp2_port_link_mode { 1642 const enum ethtool_link_mode_bit_indices *mask_ethtool; 1643 int m_ethtool_len; 1644 u32 mask; 1645 u32 speed; 1646 u32 width; 1647 u8 mask_sup_width; 1648 }; 1649 1650 static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { 1651 { 1652 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_SGMII_100M, 1653 .mask_ethtool = mlxsw_sp2_mask_ethtool_sgmii_100m, 1654 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_SGMII_100M_LEN, 1655 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_1X | 1656 MLXSW_SP_PORT_MASK_WIDTH_2X | 1657 MLXSW_SP_PORT_MASK_WIDTH_4X | 1658 MLXSW_SP_PORT_MASK_WIDTH_8X, 1659 .speed = SPEED_100, 1660 .width = 1, 1661 }, 1662 { 1663 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_1000BASE_X_SGMII, 1664 .mask_ethtool = mlxsw_sp2_mask_ethtool_1000base_x_sgmii, 1665 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_1000BASE_X_SGMII_LEN, 1666 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_1X | 1667 MLXSW_SP_PORT_MASK_WIDTH_2X | 1668 MLXSW_SP_PORT_MASK_WIDTH_4X | 1669 MLXSW_SP_PORT_MASK_WIDTH_8X, 1670 .speed = SPEED_1000, 1671 .width = 1, 1672 }, 1673 { 1674 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_5GBASE_R, 1675 .mask_ethtool = mlxsw_sp2_mask_ethtool_5gbase_r, 1676 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_5GBASE_R_LEN, 1677 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_1X | 1678 MLXSW_SP_PORT_MASK_WIDTH_2X | 1679 MLXSW_SP_PORT_MASK_WIDTH_4X | 1680 MLXSW_SP_PORT_MASK_WIDTH_8X, 1681 .speed = SPEED_5000, 1682 .width = 1, 1683 }, 1684 { 1685 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_XFI_XAUI_1_10G, 1686 .mask_ethtool = mlxsw_sp2_mask_ethtool_xfi_xaui_1_10g, 1687 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_XFI_XAUI_1_10G_LEN, 1688 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_1X | 1689 MLXSW_SP_PORT_MASK_WIDTH_2X | 1690 MLXSW_SP_PORT_MASK_WIDTH_4X | 1691 MLXSW_SP_PORT_MASK_WIDTH_8X, 1692 .speed = SPEED_10000, 1693 .width = 1, 1694 }, 1695 { 1696 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_XLAUI_4_XLPPI_4_40G, 1697 .mask_ethtool = mlxsw_sp2_mask_ethtool_xlaui_4_xlppi_4_40g, 1698 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_XLAUI_4_XLPPI_4_40G_LEN, 1699 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_4X | 1700 MLXSW_SP_PORT_MASK_WIDTH_8X, 1701 .speed = SPEED_40000, 1702 .width = 4, 1703 }, 1704 { 1705 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_25GAUI_1_25GBASE_CR_KR, 1706 .mask_ethtool = mlxsw_sp2_mask_ethtool_25gaui_1_25gbase_cr_kr, 1707 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_25GAUI_1_25GBASE_CR_KR_LEN, 1708 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_1X | 1709 MLXSW_SP_PORT_MASK_WIDTH_2X | 1710 MLXSW_SP_PORT_MASK_WIDTH_4X | 1711 MLXSW_SP_PORT_MASK_WIDTH_8X, 1712 .speed = SPEED_25000, 1713 .width = 1, 1714 }, 1715 { 1716 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_50GAUI_2_LAUI_2_50GBASE_CR2_KR2, 1717 .mask_ethtool = mlxsw_sp2_mask_ethtool_50gaui_2_laui_2_50gbase_cr2_kr2, 1718 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_50GAUI_2_LAUI_2_50GBASE_CR2_KR2_LEN, 1719 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_2X | 1720 MLXSW_SP_PORT_MASK_WIDTH_4X | 1721 MLXSW_SP_PORT_MASK_WIDTH_8X, 1722 .speed = SPEED_50000, 1723 .width = 2, 1724 }, 1725 { 1726 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_50GAUI_1_LAUI_1_50GBASE_CR_KR, 1727 .mask_ethtool = mlxsw_sp2_mask_ethtool_50gaui_1_laui_1_50gbase_cr_kr, 1728 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_50GAUI_1_LAUI_1_50GBASE_CR_KR_LEN, 1729 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_1X, 1730 .speed = SPEED_50000, 1731 .width = 1, 1732 }, 1733 { 1734 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_CAUI_4_100GBASE_CR4_KR4, 1735 .mask_ethtool = mlxsw_sp2_mask_ethtool_caui_4_100gbase_cr4_kr4, 1736 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_CAUI_4_100GBASE_CR4_KR4_LEN, 1737 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_4X | 1738 MLXSW_SP_PORT_MASK_WIDTH_8X, 1739 .speed = SPEED_100000, 1740 .width = 4, 1741 }, 1742 { 1743 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_100GAUI_2_100GBASE_CR2_KR2, 1744 .mask_ethtool = mlxsw_sp2_mask_ethtool_100gaui_2_100gbase_cr2_kr2, 1745 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_100GAUI_2_100GBASE_CR2_KR2_LEN, 1746 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_2X, 1747 .speed = SPEED_100000, 1748 .width = 2, 1749 }, 1750 { 1751 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_200GAUI_4_200GBASE_CR4_KR4, 1752 .mask_ethtool = mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4, 1753 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_200GAUI_4_200GBASE_CR4_KR4_LEN, 1754 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_4X | 1755 MLXSW_SP_PORT_MASK_WIDTH_8X, 1756 .speed = SPEED_200000, 1757 .width = 4, 1758 }, 1759 { 1760 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_400GAUI_8, 1761 .mask_ethtool = mlxsw_sp2_mask_ethtool_400gaui_8, 1762 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_400GAUI_8_LEN, 1763 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_8X, 1764 .speed = SPEED_400000, 1765 .width = 8, 1766 }, 1767 }; 1768 1769 #define MLXSW_SP2_PORT_LINK_MODE_LEN ARRAY_SIZE(mlxsw_sp2_port_link_mode) 1770 1771 static void 1772 mlxsw_sp2_from_ptys_supported_port(struct mlxsw_sp *mlxsw_sp, 1773 u32 ptys_eth_proto, 1774 struct ethtool_link_ksettings *cmd) 1775 { 1776 ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); 1777 ethtool_link_ksettings_add_link_mode(cmd, supported, Backplane); 1778 } 1779 1780 static void 1781 mlxsw_sp2_set_bit_ethtool(const struct mlxsw_sp2_port_link_mode *link_mode, 1782 unsigned long *mode) 1783 { 1784 int i; 1785 1786 for (i = 0; i < link_mode->m_ethtool_len; i++) 1787 __set_bit(link_mode->mask_ethtool[i], mode); 1788 } 1789 1790 static void 1791 mlxsw_sp2_from_ptys_link(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto, 1792 unsigned long *mode) 1793 { 1794 int i; 1795 1796 for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) { 1797 if (ptys_eth_proto & mlxsw_sp2_port_link_mode[i].mask) 1798 mlxsw_sp2_set_bit_ethtool(&mlxsw_sp2_port_link_mode[i], 1799 mode); 1800 } 1801 } 1802 1803 static u32 1804 mlxsw_sp2_from_ptys_speed(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto) 1805 { 1806 int i; 1807 1808 for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) { 1809 if (ptys_eth_proto & mlxsw_sp2_port_link_mode[i].mask) 1810 return mlxsw_sp2_port_link_mode[i].speed; 1811 } 1812 1813 return SPEED_UNKNOWN; 1814 } 1815 1816 static void 1817 mlxsw_sp2_from_ptys_link_mode(struct mlxsw_sp *mlxsw_sp, bool carrier_ok, 1818 u32 ptys_eth_proto, 1819 struct ethtool_link_ksettings *cmd) 1820 { 1821 struct mlxsw_sp2_port_link_mode link; 1822 int i; 1823 1824 cmd->base.speed = SPEED_UNKNOWN; 1825 cmd->base.duplex = DUPLEX_UNKNOWN; 1826 cmd->lanes = 0; 1827 1828 if (!carrier_ok) 1829 return; 1830 1831 for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) { 1832 if (ptys_eth_proto & mlxsw_sp2_port_link_mode[i].mask) { 1833 link = mlxsw_sp2_port_link_mode[i]; 1834 ethtool_params_from_link_mode(cmd, 1835 link.mask_ethtool[1]); 1836 } 1837 } 1838 } 1839 1840 static int mlxsw_sp2_ptys_max_speed(struct mlxsw_sp_port *mlxsw_sp_port, u32 *p_max_speed) 1841 { 1842 u32 eth_proto_cap; 1843 u32 max_speed = 0; 1844 int err; 1845 int i; 1846 1847 err = mlxsw_sp_port_ptys_query(mlxsw_sp_port, ð_proto_cap, NULL, NULL, NULL); 1848 if (err) 1849 return err; 1850 1851 for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) { 1852 if ((eth_proto_cap & mlxsw_sp2_port_link_mode[i].mask) && 1853 mlxsw_sp2_port_link_mode[i].speed > max_speed) 1854 max_speed = mlxsw_sp2_port_link_mode[i].speed; 1855 } 1856 1857 *p_max_speed = max_speed; 1858 return 0; 1859 } 1860 1861 static bool 1862 mlxsw_sp2_test_bit_ethtool(const struct mlxsw_sp2_port_link_mode *link_mode, 1863 const unsigned long *mode) 1864 { 1865 int cnt = 0; 1866 int i; 1867 1868 for (i = 0; i < link_mode->m_ethtool_len; i++) { 1869 if (test_bit(link_mode->mask_ethtool[i], mode)) 1870 cnt++; 1871 } 1872 1873 return cnt == link_mode->m_ethtool_len; 1874 } 1875 1876 static u32 1877 mlxsw_sp2_to_ptys_advert_link(struct mlxsw_sp *mlxsw_sp, 1878 const struct ethtool_link_ksettings *cmd) 1879 { 1880 u32 ptys_proto = 0; 1881 int i; 1882 1883 for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) { 1884 if (mlxsw_sp2_test_bit_ethtool(&mlxsw_sp2_port_link_mode[i], 1885 cmd->link_modes.advertising)) 1886 ptys_proto |= mlxsw_sp2_port_link_mode[i].mask; 1887 } 1888 return ptys_proto; 1889 } 1890 1891 static u32 mlxsw_sp2_to_ptys_speed_lanes(struct mlxsw_sp *mlxsw_sp, u8 width, 1892 const struct ethtool_link_ksettings *cmd) 1893 { 1894 u8 mask_width = mlxsw_sp_port_mask_width_get(width); 1895 struct mlxsw_sp2_port_link_mode link_mode; 1896 u32 ptys_proto = 0; 1897 int i; 1898 1899 if (cmd->lanes > width) 1900 return ptys_proto; 1901 1902 for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) { 1903 if (cmd->base.speed == mlxsw_sp2_port_link_mode[i].speed) { 1904 link_mode = mlxsw_sp2_port_link_mode[i]; 1905 1906 if (!cmd->lanes) { 1907 /* If number of lanes was not set by user space, 1908 * choose the link mode that supports the width 1909 * of the port. 1910 */ 1911 if (mask_width & link_mode.mask_sup_width) 1912 ptys_proto |= link_mode.mask; 1913 } else if (cmd->lanes == link_mode.width) { 1914 /* Else if the number of lanes was set, choose 1915 * the link mode that its actual width equals to 1916 * it. 1917 */ 1918 ptys_proto |= link_mode.mask; 1919 } 1920 } 1921 } 1922 return ptys_proto; 1923 } 1924 1925 static void 1926 mlxsw_sp2_reg_ptys_eth_pack(struct mlxsw_sp *mlxsw_sp, char *payload, 1927 u8 local_port, u32 proto_admin, 1928 bool autoneg) 1929 { 1930 mlxsw_reg_ptys_ext_eth_pack(payload, local_port, proto_admin, autoneg); 1931 } 1932 1933 static void 1934 mlxsw_sp2_reg_ptys_eth_unpack(struct mlxsw_sp *mlxsw_sp, char *payload, 1935 u32 *p_eth_proto_cap, u32 *p_eth_proto_admin, 1936 u32 *p_eth_proto_oper) 1937 { 1938 mlxsw_reg_ptys_ext_eth_unpack(payload, p_eth_proto_cap, 1939 p_eth_proto_admin, p_eth_proto_oper); 1940 } 1941 1942 static u32 mlxsw_sp2_ptys_proto_cap_masked_get(u32 eth_proto_cap) 1943 { 1944 u32 ptys_proto_cap_masked = 0; 1945 int i; 1946 1947 for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) { 1948 if (mlxsw_sp2_port_link_mode[i].mask & eth_proto_cap) 1949 ptys_proto_cap_masked |= 1950 mlxsw_sp2_port_link_mode[i].mask; 1951 } 1952 1953 return ptys_proto_cap_masked; 1954 } 1955 1956 const struct mlxsw_sp_port_type_speed_ops mlxsw_sp2_port_type_speed_ops = { 1957 .from_ptys_supported_port = mlxsw_sp2_from_ptys_supported_port, 1958 .from_ptys_link = mlxsw_sp2_from_ptys_link, 1959 .from_ptys_speed = mlxsw_sp2_from_ptys_speed, 1960 .from_ptys_link_mode = mlxsw_sp2_from_ptys_link_mode, 1961 .ptys_max_speed = mlxsw_sp2_ptys_max_speed, 1962 .to_ptys_advert_link = mlxsw_sp2_to_ptys_advert_link, 1963 .to_ptys_speed_lanes = mlxsw_sp2_to_ptys_speed_lanes, 1964 .reg_ptys_eth_pack = mlxsw_sp2_reg_ptys_eth_pack, 1965 .reg_ptys_eth_unpack = mlxsw_sp2_reg_ptys_eth_unpack, 1966 .ptys_proto_cap_masked_get = mlxsw_sp2_ptys_proto_cap_masked_get, 1967 }; 1968