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