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_SGMII | 997 MLXSW_REG_PTYS_ETH_SPEED_1000BASE_KX, 998 .mask_ethtool = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, 999 .speed = SPEED_1000, 1000 }, 1001 { 1002 .mask = MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CX4 | 1003 MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4, 1004 .mask_ethtool = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, 1005 .speed = SPEED_10000, 1006 }, 1007 { 1008 .mask = MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR | 1009 MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR | 1010 MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR | 1011 MLXSW_REG_PTYS_ETH_SPEED_10GBASE_ER_LR, 1012 .mask_ethtool = ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, 1013 .speed = SPEED_10000, 1014 }, 1015 { 1016 .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4, 1017 .mask_ethtool = ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, 1018 .speed = SPEED_40000, 1019 }, 1020 { 1021 .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4, 1022 .mask_ethtool = ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, 1023 .speed = SPEED_40000, 1024 }, 1025 { 1026 .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4, 1027 .mask_ethtool = ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, 1028 .speed = SPEED_40000, 1029 }, 1030 { 1031 .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_LR4_ER4, 1032 .mask_ethtool = ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, 1033 .speed = SPEED_40000, 1034 }, 1035 { 1036 .mask = MLXSW_REG_PTYS_ETH_SPEED_25GBASE_CR, 1037 .mask_ethtool = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, 1038 .speed = SPEED_25000, 1039 }, 1040 { 1041 .mask = MLXSW_REG_PTYS_ETH_SPEED_25GBASE_KR, 1042 .mask_ethtool = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, 1043 .speed = SPEED_25000, 1044 }, 1045 { 1046 .mask = MLXSW_REG_PTYS_ETH_SPEED_25GBASE_SR, 1047 .mask_ethtool = ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, 1048 .speed = SPEED_25000, 1049 }, 1050 { 1051 .mask = MLXSW_REG_PTYS_ETH_SPEED_50GBASE_CR2, 1052 .mask_ethtool = ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, 1053 .speed = SPEED_50000, 1054 }, 1055 { 1056 .mask = MLXSW_REG_PTYS_ETH_SPEED_50GBASE_KR2, 1057 .mask_ethtool = ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, 1058 .speed = SPEED_50000, 1059 }, 1060 { 1061 .mask = MLXSW_REG_PTYS_ETH_SPEED_50GBASE_SR2, 1062 .mask_ethtool = ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, 1063 .speed = SPEED_50000, 1064 }, 1065 { 1066 .mask = MLXSW_REG_PTYS_ETH_SPEED_100GBASE_CR4, 1067 .mask_ethtool = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, 1068 .speed = SPEED_100000, 1069 }, 1070 { 1071 .mask = MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4, 1072 .mask_ethtool = ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, 1073 .speed = SPEED_100000, 1074 }, 1075 { 1076 .mask = MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4, 1077 .mask_ethtool = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, 1078 .speed = SPEED_100000, 1079 }, 1080 }; 1081 1082 #define MLXSW_SP1_PORT_LINK_MODE_LEN ARRAY_SIZE(mlxsw_sp1_port_link_mode) 1083 1084 static void 1085 mlxsw_sp1_from_ptys_supported_port(struct mlxsw_sp *mlxsw_sp, 1086 u32 ptys_eth_proto, 1087 struct ethtool_link_ksettings *cmd) 1088 { 1089 if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR | 1090 MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR | 1091 MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4 | 1092 MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4 | 1093 MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4 | 1094 MLXSW_REG_PTYS_ETH_SPEED_SGMII)) 1095 ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); 1096 1097 if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR | 1098 MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4 | 1099 MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4 | 1100 MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4 | 1101 MLXSW_REG_PTYS_ETH_SPEED_1000BASE_KX)) 1102 ethtool_link_ksettings_add_link_mode(cmd, supported, Backplane); 1103 } 1104 1105 static void 1106 mlxsw_sp1_from_ptys_link(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto, 1107 u8 width, unsigned long *mode) 1108 { 1109 int i; 1110 1111 for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) { 1112 if (ptys_eth_proto & mlxsw_sp1_port_link_mode[i].mask) 1113 __set_bit(mlxsw_sp1_port_link_mode[i].mask_ethtool, 1114 mode); 1115 } 1116 } 1117 1118 static u32 1119 mlxsw_sp1_from_ptys_speed(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto) 1120 { 1121 int i; 1122 1123 for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) { 1124 if (ptys_eth_proto & mlxsw_sp1_port_link_mode[i].mask) 1125 return mlxsw_sp1_port_link_mode[i].speed; 1126 } 1127 1128 return SPEED_UNKNOWN; 1129 } 1130 1131 static void 1132 mlxsw_sp1_from_ptys_speed_duplex(struct mlxsw_sp *mlxsw_sp, bool carrier_ok, 1133 u32 ptys_eth_proto, 1134 struct ethtool_link_ksettings *cmd) 1135 { 1136 cmd->base.speed = SPEED_UNKNOWN; 1137 cmd->base.duplex = DUPLEX_UNKNOWN; 1138 1139 if (!carrier_ok) 1140 return; 1141 1142 cmd->base.speed = mlxsw_sp1_from_ptys_speed(mlxsw_sp, ptys_eth_proto); 1143 if (cmd->base.speed != SPEED_UNKNOWN) 1144 cmd->base.duplex = DUPLEX_FULL; 1145 } 1146 1147 static u32 1148 mlxsw_sp1_to_ptys_advert_link(struct mlxsw_sp *mlxsw_sp, u8 width, 1149 const struct ethtool_link_ksettings *cmd) 1150 { 1151 u32 ptys_proto = 0; 1152 int i; 1153 1154 for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) { 1155 if (test_bit(mlxsw_sp1_port_link_mode[i].mask_ethtool, 1156 cmd->link_modes.advertising)) 1157 ptys_proto |= mlxsw_sp1_port_link_mode[i].mask; 1158 } 1159 return ptys_proto; 1160 } 1161 1162 static u32 mlxsw_sp1_to_ptys_speed(struct mlxsw_sp *mlxsw_sp, u8 width, 1163 u32 speed) 1164 { 1165 u32 ptys_proto = 0; 1166 int i; 1167 1168 for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) { 1169 if (speed == mlxsw_sp1_port_link_mode[i].speed) 1170 ptys_proto |= mlxsw_sp1_port_link_mode[i].mask; 1171 } 1172 return ptys_proto; 1173 } 1174 1175 static void 1176 mlxsw_sp1_reg_ptys_eth_pack(struct mlxsw_sp *mlxsw_sp, char *payload, 1177 u8 local_port, u32 proto_admin, bool autoneg) 1178 { 1179 mlxsw_reg_ptys_eth_pack(payload, local_port, proto_admin, autoneg); 1180 } 1181 1182 static void 1183 mlxsw_sp1_reg_ptys_eth_unpack(struct mlxsw_sp *mlxsw_sp, char *payload, 1184 u32 *p_eth_proto_cap, u32 *p_eth_proto_admin, 1185 u32 *p_eth_proto_oper) 1186 { 1187 mlxsw_reg_ptys_eth_unpack(payload, p_eth_proto_cap, p_eth_proto_admin, 1188 p_eth_proto_oper); 1189 } 1190 1191 const struct mlxsw_sp_port_type_speed_ops mlxsw_sp1_port_type_speed_ops = { 1192 .from_ptys_supported_port = mlxsw_sp1_from_ptys_supported_port, 1193 .from_ptys_link = mlxsw_sp1_from_ptys_link, 1194 .from_ptys_speed = mlxsw_sp1_from_ptys_speed, 1195 .from_ptys_speed_duplex = mlxsw_sp1_from_ptys_speed_duplex, 1196 .to_ptys_advert_link = mlxsw_sp1_to_ptys_advert_link, 1197 .to_ptys_speed = mlxsw_sp1_to_ptys_speed, 1198 .reg_ptys_eth_pack = mlxsw_sp1_reg_ptys_eth_pack, 1199 .reg_ptys_eth_unpack = mlxsw_sp1_reg_ptys_eth_unpack, 1200 }; 1201 1202 static const enum ethtool_link_mode_bit_indices 1203 mlxsw_sp2_mask_ethtool_sgmii_100m[] = { 1204 ETHTOOL_LINK_MODE_100baseT_Full_BIT, 1205 }; 1206 1207 #define MLXSW_SP2_MASK_ETHTOOL_SGMII_100M_LEN \ 1208 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_sgmii_100m) 1209 1210 static const enum ethtool_link_mode_bit_indices 1211 mlxsw_sp2_mask_ethtool_1000base_x_sgmii[] = { 1212 ETHTOOL_LINK_MODE_1000baseT_Full_BIT, 1213 ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, 1214 }; 1215 1216 #define MLXSW_SP2_MASK_ETHTOOL_1000BASE_X_SGMII_LEN \ 1217 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_1000base_x_sgmii) 1218 1219 static const enum ethtool_link_mode_bit_indices 1220 mlxsw_sp2_mask_ethtool_5gbase_r[] = { 1221 ETHTOOL_LINK_MODE_5000baseT_Full_BIT, 1222 }; 1223 1224 #define MLXSW_SP2_MASK_ETHTOOL_5GBASE_R_LEN \ 1225 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_5gbase_r) 1226 1227 static const enum ethtool_link_mode_bit_indices 1228 mlxsw_sp2_mask_ethtool_xfi_xaui_1_10g[] = { 1229 ETHTOOL_LINK_MODE_10000baseT_Full_BIT, 1230 ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, 1231 ETHTOOL_LINK_MODE_10000baseR_FEC_BIT, 1232 ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, 1233 ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, 1234 ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, 1235 ETHTOOL_LINK_MODE_10000baseER_Full_BIT, 1236 }; 1237 1238 #define MLXSW_SP2_MASK_ETHTOOL_XFI_XAUI_1_10G_LEN \ 1239 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_xfi_xaui_1_10g) 1240 1241 static const enum ethtool_link_mode_bit_indices 1242 mlxsw_sp2_mask_ethtool_xlaui_4_xlppi_4_40g[] = { 1243 ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, 1244 ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, 1245 ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, 1246 ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, 1247 }; 1248 1249 #define MLXSW_SP2_MASK_ETHTOOL_XLAUI_4_XLPPI_4_40G_LEN \ 1250 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_xlaui_4_xlppi_4_40g) 1251 1252 static const enum ethtool_link_mode_bit_indices 1253 mlxsw_sp2_mask_ethtool_25gaui_1_25gbase_cr_kr[] = { 1254 ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, 1255 ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, 1256 ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, 1257 }; 1258 1259 #define MLXSW_SP2_MASK_ETHTOOL_25GAUI_1_25GBASE_CR_KR_LEN \ 1260 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_25gaui_1_25gbase_cr_kr) 1261 1262 static const enum ethtool_link_mode_bit_indices 1263 mlxsw_sp2_mask_ethtool_50gaui_2_laui_2_50gbase_cr2_kr2[] = { 1264 ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, 1265 ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, 1266 ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, 1267 }; 1268 1269 #define MLXSW_SP2_MASK_ETHTOOL_50GAUI_2_LAUI_2_50GBASE_CR2_KR2_LEN \ 1270 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_50gaui_2_laui_2_50gbase_cr2_kr2) 1271 1272 static const enum ethtool_link_mode_bit_indices 1273 mlxsw_sp2_mask_ethtool_50gaui_1_laui_1_50gbase_cr_kr[] = { 1274 ETHTOOL_LINK_MODE_50000baseKR_Full_BIT, 1275 ETHTOOL_LINK_MODE_50000baseSR_Full_BIT, 1276 ETHTOOL_LINK_MODE_50000baseCR_Full_BIT, 1277 ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT, 1278 ETHTOOL_LINK_MODE_50000baseDR_Full_BIT, 1279 }; 1280 1281 #define MLXSW_SP2_MASK_ETHTOOL_50GAUI_1_LAUI_1_50GBASE_CR_KR_LEN \ 1282 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_50gaui_1_laui_1_50gbase_cr_kr) 1283 1284 static const enum ethtool_link_mode_bit_indices 1285 mlxsw_sp2_mask_ethtool_caui_4_100gbase_cr4_kr4[] = { 1286 ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, 1287 ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, 1288 ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, 1289 ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT, 1290 }; 1291 1292 #define MLXSW_SP2_MASK_ETHTOOL_CAUI_4_100GBASE_CR4_KR4_LEN \ 1293 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_caui_4_100gbase_cr4_kr4) 1294 1295 static const enum ethtool_link_mode_bit_indices 1296 mlxsw_sp2_mask_ethtool_100gaui_2_100gbase_cr2_kr2[] = { 1297 ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT, 1298 ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT, 1299 ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT, 1300 ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT, 1301 ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT, 1302 }; 1303 1304 #define MLXSW_SP2_MASK_ETHTOOL_100GAUI_2_100GBASE_CR2_KR2_LEN \ 1305 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_100gaui_2_100gbase_cr2_kr2) 1306 1307 static const enum ethtool_link_mode_bit_indices 1308 mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4[] = { 1309 ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT, 1310 ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT, 1311 ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT, 1312 ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT, 1313 ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT, 1314 }; 1315 1316 #define MLXSW_SP2_MASK_ETHTOOL_200GAUI_4_200GBASE_CR4_KR4_LEN \ 1317 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4) 1318 1319 static const enum ethtool_link_mode_bit_indices 1320 mlxsw_sp2_mask_ethtool_400gaui_8[] = { 1321 ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT, 1322 ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT, 1323 ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT, 1324 ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT, 1325 ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT, 1326 }; 1327 1328 #define MLXSW_SP2_MASK_ETHTOOL_400GAUI_8_LEN \ 1329 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_400gaui_8) 1330 1331 #define MLXSW_SP_PORT_MASK_WIDTH_1X BIT(0) 1332 #define MLXSW_SP_PORT_MASK_WIDTH_2X BIT(1) 1333 #define MLXSW_SP_PORT_MASK_WIDTH_4X BIT(2) 1334 #define MLXSW_SP_PORT_MASK_WIDTH_8X BIT(3) 1335 1336 static u8 mlxsw_sp_port_mask_width_get(u8 width) 1337 { 1338 switch (width) { 1339 case 1: 1340 return MLXSW_SP_PORT_MASK_WIDTH_1X; 1341 case 2: 1342 return MLXSW_SP_PORT_MASK_WIDTH_2X; 1343 case 4: 1344 return MLXSW_SP_PORT_MASK_WIDTH_4X; 1345 case 8: 1346 return MLXSW_SP_PORT_MASK_WIDTH_8X; 1347 default: 1348 WARN_ON_ONCE(1); 1349 return 0; 1350 } 1351 } 1352 1353 struct mlxsw_sp2_port_link_mode { 1354 const enum ethtool_link_mode_bit_indices *mask_ethtool; 1355 int m_ethtool_len; 1356 u32 mask; 1357 u32 speed; 1358 u8 mask_width; 1359 }; 1360 1361 static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { 1362 { 1363 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_SGMII_100M, 1364 .mask_ethtool = mlxsw_sp2_mask_ethtool_sgmii_100m, 1365 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_SGMII_100M_LEN, 1366 .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | 1367 MLXSW_SP_PORT_MASK_WIDTH_2X | 1368 MLXSW_SP_PORT_MASK_WIDTH_4X | 1369 MLXSW_SP_PORT_MASK_WIDTH_8X, 1370 .speed = SPEED_100, 1371 }, 1372 { 1373 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_1000BASE_X_SGMII, 1374 .mask_ethtool = mlxsw_sp2_mask_ethtool_1000base_x_sgmii, 1375 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_1000BASE_X_SGMII_LEN, 1376 .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | 1377 MLXSW_SP_PORT_MASK_WIDTH_2X | 1378 MLXSW_SP_PORT_MASK_WIDTH_4X | 1379 MLXSW_SP_PORT_MASK_WIDTH_8X, 1380 .speed = SPEED_1000, 1381 }, 1382 { 1383 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_5GBASE_R, 1384 .mask_ethtool = mlxsw_sp2_mask_ethtool_5gbase_r, 1385 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_5GBASE_R_LEN, 1386 .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | 1387 MLXSW_SP_PORT_MASK_WIDTH_2X | 1388 MLXSW_SP_PORT_MASK_WIDTH_4X | 1389 MLXSW_SP_PORT_MASK_WIDTH_8X, 1390 .speed = SPEED_5000, 1391 }, 1392 { 1393 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_XFI_XAUI_1_10G, 1394 .mask_ethtool = mlxsw_sp2_mask_ethtool_xfi_xaui_1_10g, 1395 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_XFI_XAUI_1_10G_LEN, 1396 .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | 1397 MLXSW_SP_PORT_MASK_WIDTH_2X | 1398 MLXSW_SP_PORT_MASK_WIDTH_4X | 1399 MLXSW_SP_PORT_MASK_WIDTH_8X, 1400 .speed = SPEED_10000, 1401 }, 1402 { 1403 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_XLAUI_4_XLPPI_4_40G, 1404 .mask_ethtool = mlxsw_sp2_mask_ethtool_xlaui_4_xlppi_4_40g, 1405 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_XLAUI_4_XLPPI_4_40G_LEN, 1406 .mask_width = MLXSW_SP_PORT_MASK_WIDTH_4X | 1407 MLXSW_SP_PORT_MASK_WIDTH_8X, 1408 .speed = SPEED_40000, 1409 }, 1410 { 1411 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_25GAUI_1_25GBASE_CR_KR, 1412 .mask_ethtool = mlxsw_sp2_mask_ethtool_25gaui_1_25gbase_cr_kr, 1413 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_25GAUI_1_25GBASE_CR_KR_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_25000, 1419 }, 1420 { 1421 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_50GAUI_2_LAUI_2_50GBASE_CR2_KR2, 1422 .mask_ethtool = mlxsw_sp2_mask_ethtool_50gaui_2_laui_2_50gbase_cr2_kr2, 1423 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_50GAUI_2_LAUI_2_50GBASE_CR2_KR2_LEN, 1424 .mask_width = MLXSW_SP_PORT_MASK_WIDTH_2X | 1425 MLXSW_SP_PORT_MASK_WIDTH_4X | 1426 MLXSW_SP_PORT_MASK_WIDTH_8X, 1427 .speed = SPEED_50000, 1428 }, 1429 { 1430 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_50GAUI_1_LAUI_1_50GBASE_CR_KR, 1431 .mask_ethtool = mlxsw_sp2_mask_ethtool_50gaui_1_laui_1_50gbase_cr_kr, 1432 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_50GAUI_1_LAUI_1_50GBASE_CR_KR_LEN, 1433 .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X, 1434 .speed = SPEED_50000, 1435 }, 1436 { 1437 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_CAUI_4_100GBASE_CR4_KR4, 1438 .mask_ethtool = mlxsw_sp2_mask_ethtool_caui_4_100gbase_cr4_kr4, 1439 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_CAUI_4_100GBASE_CR4_KR4_LEN, 1440 .mask_width = MLXSW_SP_PORT_MASK_WIDTH_4X | 1441 MLXSW_SP_PORT_MASK_WIDTH_8X, 1442 .speed = SPEED_100000, 1443 }, 1444 { 1445 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_100GAUI_2_100GBASE_CR2_KR2, 1446 .mask_ethtool = mlxsw_sp2_mask_ethtool_100gaui_2_100gbase_cr2_kr2, 1447 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_100GAUI_2_100GBASE_CR2_KR2_LEN, 1448 .mask_width = MLXSW_SP_PORT_MASK_WIDTH_2X, 1449 .speed = SPEED_100000, 1450 }, 1451 { 1452 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_200GAUI_4_200GBASE_CR4_KR4, 1453 .mask_ethtool = mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4, 1454 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_200GAUI_4_200GBASE_CR4_KR4_LEN, 1455 .mask_width = MLXSW_SP_PORT_MASK_WIDTH_4X | 1456 MLXSW_SP_PORT_MASK_WIDTH_8X, 1457 .speed = SPEED_200000, 1458 }, 1459 { 1460 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_400GAUI_8, 1461 .mask_ethtool = mlxsw_sp2_mask_ethtool_400gaui_8, 1462 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_400GAUI_8_LEN, 1463 .mask_width = MLXSW_SP_PORT_MASK_WIDTH_8X, 1464 .speed = SPEED_400000, 1465 }, 1466 }; 1467 1468 #define MLXSW_SP2_PORT_LINK_MODE_LEN ARRAY_SIZE(mlxsw_sp2_port_link_mode) 1469 1470 static void 1471 mlxsw_sp2_from_ptys_supported_port(struct mlxsw_sp *mlxsw_sp, 1472 u32 ptys_eth_proto, 1473 struct ethtool_link_ksettings *cmd) 1474 { 1475 ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); 1476 ethtool_link_ksettings_add_link_mode(cmd, supported, Backplane); 1477 } 1478 1479 static void 1480 mlxsw_sp2_set_bit_ethtool(const struct mlxsw_sp2_port_link_mode *link_mode, 1481 unsigned long *mode) 1482 { 1483 int i; 1484 1485 for (i = 0; i < link_mode->m_ethtool_len; i++) 1486 __set_bit(link_mode->mask_ethtool[i], mode); 1487 } 1488 1489 static void 1490 mlxsw_sp2_from_ptys_link(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto, 1491 u8 width, unsigned long *mode) 1492 { 1493 u8 mask_width = mlxsw_sp_port_mask_width_get(width); 1494 int i; 1495 1496 for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) { 1497 if ((ptys_eth_proto & mlxsw_sp2_port_link_mode[i].mask) && 1498 (mask_width & mlxsw_sp2_port_link_mode[i].mask_width)) 1499 mlxsw_sp2_set_bit_ethtool(&mlxsw_sp2_port_link_mode[i], 1500 mode); 1501 } 1502 } 1503 1504 static u32 1505 mlxsw_sp2_from_ptys_speed(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto) 1506 { 1507 int i; 1508 1509 for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) { 1510 if (ptys_eth_proto & mlxsw_sp2_port_link_mode[i].mask) 1511 return mlxsw_sp2_port_link_mode[i].speed; 1512 } 1513 1514 return SPEED_UNKNOWN; 1515 } 1516 1517 static void 1518 mlxsw_sp2_from_ptys_speed_duplex(struct mlxsw_sp *mlxsw_sp, bool carrier_ok, 1519 u32 ptys_eth_proto, 1520 struct ethtool_link_ksettings *cmd) 1521 { 1522 cmd->base.speed = SPEED_UNKNOWN; 1523 cmd->base.duplex = DUPLEX_UNKNOWN; 1524 1525 if (!carrier_ok) 1526 return; 1527 1528 cmd->base.speed = mlxsw_sp2_from_ptys_speed(mlxsw_sp, ptys_eth_proto); 1529 if (cmd->base.speed != SPEED_UNKNOWN) 1530 cmd->base.duplex = DUPLEX_FULL; 1531 } 1532 1533 static bool 1534 mlxsw_sp2_test_bit_ethtool(const struct mlxsw_sp2_port_link_mode *link_mode, 1535 const unsigned long *mode) 1536 { 1537 int cnt = 0; 1538 int i; 1539 1540 for (i = 0; i < link_mode->m_ethtool_len; i++) { 1541 if (test_bit(link_mode->mask_ethtool[i], mode)) 1542 cnt++; 1543 } 1544 1545 return cnt == link_mode->m_ethtool_len; 1546 } 1547 1548 static u32 1549 mlxsw_sp2_to_ptys_advert_link(struct mlxsw_sp *mlxsw_sp, u8 width, 1550 const struct ethtool_link_ksettings *cmd) 1551 { 1552 u8 mask_width = mlxsw_sp_port_mask_width_get(width); 1553 u32 ptys_proto = 0; 1554 int i; 1555 1556 for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) { 1557 if ((mask_width & mlxsw_sp2_port_link_mode[i].mask_width) && 1558 mlxsw_sp2_test_bit_ethtool(&mlxsw_sp2_port_link_mode[i], 1559 cmd->link_modes.advertising)) 1560 ptys_proto |= mlxsw_sp2_port_link_mode[i].mask; 1561 } 1562 return ptys_proto; 1563 } 1564 1565 static u32 mlxsw_sp2_to_ptys_speed(struct mlxsw_sp *mlxsw_sp, 1566 u8 width, u32 speed) 1567 { 1568 u8 mask_width = mlxsw_sp_port_mask_width_get(width); 1569 u32 ptys_proto = 0; 1570 int i; 1571 1572 for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) { 1573 if ((speed == mlxsw_sp2_port_link_mode[i].speed) && 1574 (mask_width & mlxsw_sp2_port_link_mode[i].mask_width)) 1575 ptys_proto |= mlxsw_sp2_port_link_mode[i].mask; 1576 } 1577 return ptys_proto; 1578 } 1579 1580 static void 1581 mlxsw_sp2_reg_ptys_eth_pack(struct mlxsw_sp *mlxsw_sp, char *payload, 1582 u8 local_port, u32 proto_admin, 1583 bool autoneg) 1584 { 1585 mlxsw_reg_ptys_ext_eth_pack(payload, local_port, proto_admin, autoneg); 1586 } 1587 1588 static void 1589 mlxsw_sp2_reg_ptys_eth_unpack(struct mlxsw_sp *mlxsw_sp, char *payload, 1590 u32 *p_eth_proto_cap, u32 *p_eth_proto_admin, 1591 u32 *p_eth_proto_oper) 1592 { 1593 mlxsw_reg_ptys_ext_eth_unpack(payload, p_eth_proto_cap, 1594 p_eth_proto_admin, p_eth_proto_oper); 1595 } 1596 1597 const struct mlxsw_sp_port_type_speed_ops mlxsw_sp2_port_type_speed_ops = { 1598 .from_ptys_supported_port = mlxsw_sp2_from_ptys_supported_port, 1599 .from_ptys_link = mlxsw_sp2_from_ptys_link, 1600 .from_ptys_speed = mlxsw_sp2_from_ptys_speed, 1601 .from_ptys_speed_duplex = mlxsw_sp2_from_ptys_speed_duplex, 1602 .to_ptys_advert_link = mlxsw_sp2_to_ptys_advert_link, 1603 .to_ptys_speed = mlxsw_sp2_to_ptys_speed, 1604 .reg_ptys_eth_pack = mlxsw_sp2_reg_ptys_eth_pack, 1605 .reg_ptys_eth_unpack = mlxsw_sp2_reg_ptys_eth_unpack, 1606 }; 1607