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