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