cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

spectrum_ethtool.c (60550B)


      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	{1042, ETHTOOL_LINK_EXT_STATE_MODULE,
    101	 ETHTOOL_LINK_EXT_SUBSTATE_MODULE_CMIS_NOT_READY},
    102};
    103
    104static void
    105mlxsw_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
    141static int
    142mlxsw_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
    181static 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
    190static 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
    208static 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
    259err_port_pause_configure:
    260	mlxsw_sp_hdroom_configure(mlxsw_sp_port, &orig_hdroom);
    261	return err;
    262}
    263
    264struct mlxsw_sp_port_hw_stats {
    265	char str[ETH_GSTRING_LEN];
    266	u64 (*getter)(const char *payload);
    267	bool cells_bytes;
    268};
    269
    270static 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
    351static 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
    369static 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
    427static 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
    449static 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
    458static 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
    512static 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
    549static 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
    563struct mlxsw_sp_port_stats {
    564	char str[ETH_GSTRING_LEN];
    565	u64 (*getter)(struct mlxsw_sp_port *mlxsw_sp_port);
    566};
    567
    568static u64
    569mlxsw_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
    585static 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
    606static 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
    617static 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, "%.29s_%.1d",
    623			 mlxsw_sp_port_hw_tc_stats[i].str, tc);
    624		*p += ETH_GSTRING_LEN;
    625	}
    626}
    627
    628static 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
    690static 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
    713static int
    714mlxsw_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
    757static 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	mlxsw_sp_port_get_stats_raw(dev, grp, prio, ppcnt_pl);
    772	for (i = 0; i < len; i++) {
    773		data[data_index + i] = hw_stats[i].getter(ppcnt_pl);
    774		if (!hw_stats[i].cells_bytes)
    775			continue;
    776		data[data_index + i] = mlxsw_sp_cells_bytes(mlxsw_sp,
    777							    data[data_index + i]);
    778	}
    779}
    780
    781static void __mlxsw_sp_port_get_env_stats(struct net_device *dev, u64 *data, int data_index,
    782					  struct mlxsw_sp_port_stats *port_stats,
    783					  int len)
    784{
    785	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
    786	int i;
    787
    788	for (i = 0; i < len; i++)
    789		data[data_index + i] = port_stats[i].getter(mlxsw_sp_port);
    790}
    791
    792static void mlxsw_sp_port_get_stats(struct net_device *dev,
    793				    struct ethtool_stats *stats, u64 *data)
    794{
    795	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
    796	int i, data_index = 0;
    797
    798	/* IEEE 802.3 Counters */
    799	__mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT, 0,
    800				  data, data_index);
    801	data_index = MLXSW_SP_PORT_HW_STATS_LEN;
    802
    803	/* RFC 2863 Counters */
    804	__mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_RFC_2863_CNT, 0,
    805				  data, data_index);
    806	data_index += MLXSW_SP_PORT_HW_RFC_2863_STATS_LEN;
    807
    808	/* RFC 2819 Counters */
    809	__mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_RFC_2819_CNT, 0,
    810				  data, data_index);
    811	data_index += MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN;
    812
    813	/* RFC 3635 Counters */
    814	__mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_RFC_3635_CNT, 0,
    815				  data, data_index);
    816	data_index += MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN;
    817
    818	/* Extended Counters */
    819	__mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_EXT_CNT, 0,
    820				  data, data_index);
    821	data_index += MLXSW_SP_PORT_HW_EXT_STATS_LEN;
    822
    823	/* Discard Counters */
    824	__mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_DISCARD_CNT, 0,
    825				  data, data_index);
    826	data_index += MLXSW_SP_PORT_HW_DISCARD_STATS_LEN;
    827
    828	/* Per-Priority Counters */
    829	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
    830		__mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_PRIO_CNT, i,
    831					  data, data_index);
    832		data_index += MLXSW_SP_PORT_HW_PRIO_STATS_LEN;
    833	}
    834
    835	/* Per-TC Counters */
    836	for (i = 0; i < TC_MAX_QUEUE; i++) {
    837		__mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_TC_CNT, i,
    838					  data, data_index);
    839		data_index += MLXSW_SP_PORT_HW_TC_STATS_LEN;
    840	}
    841
    842	/* PTP counters */
    843	mlxsw_sp_port->mlxsw_sp->ptp_ops->get_stats(mlxsw_sp_port,
    844						    data, data_index);
    845	data_index += mlxsw_sp_port->mlxsw_sp->ptp_ops->get_stats_count();
    846
    847	/* Transceiver counters */
    848	__mlxsw_sp_port_get_env_stats(dev, data, data_index, mlxsw_sp_port_transceiver_stats,
    849				      MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN);
    850	data_index += MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN;
    851}
    852
    853static int mlxsw_sp_port_get_sset_count(struct net_device *dev, int sset)
    854{
    855	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
    856
    857	switch (sset) {
    858	case ETH_SS_STATS:
    859		return MLXSW_SP_PORT_ETHTOOL_STATS_LEN +
    860			mlxsw_sp_port->mlxsw_sp->ptp_ops->get_stats_count();
    861	default:
    862		return -EOPNOTSUPP;
    863	}
    864}
    865
    866static void
    867mlxsw_sp_port_get_link_supported(struct mlxsw_sp *mlxsw_sp, u32 eth_proto_cap,
    868				 struct ethtool_link_ksettings *cmd)
    869{
    870	const struct mlxsw_sp_port_type_speed_ops *ops;
    871
    872	ops = mlxsw_sp->port_type_speed_ops;
    873
    874	ethtool_link_ksettings_add_link_mode(cmd, supported, Asym_Pause);
    875	ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);
    876	ethtool_link_ksettings_add_link_mode(cmd, supported, Pause);
    877
    878	ops->from_ptys_supported_port(mlxsw_sp, eth_proto_cap, cmd);
    879	ops->from_ptys_link(mlxsw_sp, eth_proto_cap,
    880			    cmd->link_modes.supported);
    881}
    882
    883static void
    884mlxsw_sp_port_get_link_advertise(struct mlxsw_sp *mlxsw_sp,
    885				 u32 eth_proto_admin, bool autoneg,
    886				 struct ethtool_link_ksettings *cmd)
    887{
    888	const struct mlxsw_sp_port_type_speed_ops *ops;
    889
    890	ops = mlxsw_sp->port_type_speed_ops;
    891
    892	if (!autoneg)
    893		return;
    894
    895	ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);
    896	ops->from_ptys_link(mlxsw_sp, eth_proto_admin,
    897			    cmd->link_modes.advertising);
    898}
    899
    900static u8
    901mlxsw_sp_port_connector_port(enum mlxsw_reg_ptys_connector_type connector_type)
    902{
    903	switch (connector_type) {
    904	case MLXSW_REG_PTYS_CONNECTOR_TYPE_UNKNOWN_OR_NO_CONNECTOR:
    905		return PORT_OTHER;
    906	case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_NONE:
    907		return PORT_NONE;
    908	case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_TP:
    909		return PORT_TP;
    910	case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_AUI:
    911		return PORT_AUI;
    912	case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_BNC:
    913		return PORT_BNC;
    914	case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_MII:
    915		return PORT_MII;
    916	case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_FIBRE:
    917		return PORT_FIBRE;
    918	case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_DA:
    919		return PORT_DA;
    920	case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_OTHER:
    921		return PORT_OTHER;
    922	default:
    923		WARN_ON_ONCE(1);
    924		return PORT_OTHER;
    925	}
    926}
    927
    928static int mlxsw_sp_port_ptys_query(struct mlxsw_sp_port *mlxsw_sp_port,
    929				    u32 *p_eth_proto_cap, u32 *p_eth_proto_admin,
    930				    u32 *p_eth_proto_oper, u8 *p_connector_type)
    931{
    932	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
    933	const struct mlxsw_sp_port_type_speed_ops *ops;
    934	char ptys_pl[MLXSW_REG_PTYS_LEN];
    935	int err;
    936
    937	ops = mlxsw_sp->port_type_speed_ops;
    938
    939	ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port, 0, false);
    940	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);
    941	if (err)
    942		return err;
    943
    944	ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, p_eth_proto_cap, p_eth_proto_admin,
    945				 p_eth_proto_oper);
    946	if (p_connector_type)
    947		*p_connector_type = mlxsw_reg_ptys_connector_type_get(ptys_pl);
    948	return 0;
    949}
    950
    951static int mlxsw_sp_port_get_link_ksettings(struct net_device *dev,
    952					    struct ethtool_link_ksettings *cmd)
    953{
    954	u32 eth_proto_cap, eth_proto_admin, eth_proto_oper;
    955	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
    956	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
    957	const struct mlxsw_sp_port_type_speed_ops *ops;
    958	u8 connector_type;
    959	bool autoneg;
    960	int err;
    961
    962	err = mlxsw_sp_port_ptys_query(mlxsw_sp_port, &eth_proto_cap, &eth_proto_admin,
    963				       &eth_proto_oper, &connector_type);
    964	if (err)
    965		return err;
    966
    967	ops = mlxsw_sp->port_type_speed_ops;
    968	autoneg = mlxsw_sp_port->link.autoneg;
    969
    970	mlxsw_sp_port_get_link_supported(mlxsw_sp, eth_proto_cap, cmd);
    971
    972	mlxsw_sp_port_get_link_advertise(mlxsw_sp, eth_proto_admin, autoneg, cmd);
    973
    974	cmd->base.autoneg = autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE;
    975	cmd->base.port = mlxsw_sp_port_connector_port(connector_type);
    976	ops->from_ptys_link_mode(mlxsw_sp, netif_carrier_ok(dev),
    977				 eth_proto_oper, cmd);
    978
    979	return 0;
    980}
    981
    982static int
    983mlxsw_sp_port_set_link_ksettings(struct net_device *dev,
    984				 const struct ethtool_link_ksettings *cmd)
    985{
    986	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
    987	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
    988	const struct mlxsw_sp_port_type_speed_ops *ops;
    989	char ptys_pl[MLXSW_REG_PTYS_LEN];
    990	u32 eth_proto_cap, eth_proto_new;
    991	bool autoneg;
    992	int err;
    993
    994	ops = mlxsw_sp->port_type_speed_ops;
    995
    996	ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port,
    997			       0, false);
    998	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);
    999	if (err)
   1000		return err;
   1001	ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, &eth_proto_cap, NULL, NULL);
   1002
   1003	autoneg = cmd->base.autoneg == AUTONEG_ENABLE;
   1004	eth_proto_new = autoneg ?
   1005		ops->to_ptys_advert_link(mlxsw_sp, cmd) :
   1006		ops->to_ptys_speed_lanes(mlxsw_sp, mlxsw_sp_port->mapping.width,
   1007					 cmd);
   1008
   1009	eth_proto_new = eth_proto_new & eth_proto_cap;
   1010	if (!eth_proto_new) {
   1011		netdev_err(dev, "No supported speed or lanes requested\n");
   1012		return -EINVAL;
   1013	}
   1014
   1015	ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port,
   1016			       eth_proto_new, autoneg);
   1017	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);
   1018	if (err)
   1019		return err;
   1020
   1021	mlxsw_sp_port->link.autoneg = autoneg;
   1022
   1023	if (!netif_running(dev))
   1024		return 0;
   1025
   1026	mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false);
   1027	mlxsw_sp_port_admin_status_set(mlxsw_sp_port, true);
   1028
   1029	return 0;
   1030}
   1031
   1032static int mlxsw_sp_get_module_info(struct net_device *netdev,
   1033				    struct ethtool_modinfo *modinfo)
   1034{
   1035	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(netdev);
   1036	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
   1037
   1038	return mlxsw_env_get_module_info(netdev, mlxsw_sp->core,
   1039					 mlxsw_sp_port->mapping.slot_index,
   1040					 mlxsw_sp_port->mapping.module,
   1041					 modinfo);
   1042}
   1043
   1044static int mlxsw_sp_get_module_eeprom(struct net_device *netdev,
   1045				      struct ethtool_eeprom *ee, u8 *data)
   1046{
   1047	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(netdev);
   1048	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
   1049	u8 slot_index = mlxsw_sp_port->mapping.slot_index;
   1050	u8 module = mlxsw_sp_port->mapping.module;
   1051
   1052	return mlxsw_env_get_module_eeprom(netdev, mlxsw_sp->core, slot_index,
   1053					   module, ee, data);
   1054}
   1055
   1056static int
   1057mlxsw_sp_get_module_eeprom_by_page(struct net_device *dev,
   1058				   const struct ethtool_module_eeprom *page,
   1059				   struct netlink_ext_ack *extack)
   1060{
   1061	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
   1062	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
   1063	u8 slot_index = mlxsw_sp_port->mapping.slot_index;
   1064	u8 module = mlxsw_sp_port->mapping.module;
   1065
   1066	return mlxsw_env_get_module_eeprom_by_page(mlxsw_sp->core, slot_index,
   1067						   module, page, extack);
   1068}
   1069
   1070static int
   1071mlxsw_sp_get_ts_info(struct net_device *netdev, struct ethtool_ts_info *info)
   1072{
   1073	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(netdev);
   1074	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
   1075
   1076	return mlxsw_sp->ptp_ops->get_ts_info(mlxsw_sp, info);
   1077}
   1078
   1079static void
   1080mlxsw_sp_get_eth_phy_stats(struct net_device *dev,
   1081			   struct ethtool_eth_phy_stats *phy_stats)
   1082{
   1083	char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
   1084
   1085	if (mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT,
   1086					0, ppcnt_pl))
   1087		return;
   1088
   1089	phy_stats->SymbolErrorDuringCarrier =
   1090		mlxsw_reg_ppcnt_a_symbol_error_during_carrier_get(ppcnt_pl);
   1091}
   1092
   1093static void
   1094mlxsw_sp_get_eth_mac_stats(struct net_device *dev,
   1095			   struct ethtool_eth_mac_stats *mac_stats)
   1096{
   1097	char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
   1098
   1099	if (mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT,
   1100					0, ppcnt_pl))
   1101		return;
   1102
   1103	mac_stats->FramesTransmittedOK =
   1104		mlxsw_reg_ppcnt_a_frames_transmitted_ok_get(ppcnt_pl);
   1105	mac_stats->FramesReceivedOK =
   1106		mlxsw_reg_ppcnt_a_frames_received_ok_get(ppcnt_pl);
   1107	mac_stats->FrameCheckSequenceErrors =
   1108		mlxsw_reg_ppcnt_a_frame_check_sequence_errors_get(ppcnt_pl);
   1109	mac_stats->AlignmentErrors =
   1110		mlxsw_reg_ppcnt_a_alignment_errors_get(ppcnt_pl);
   1111	mac_stats->OctetsTransmittedOK =
   1112		mlxsw_reg_ppcnt_a_octets_transmitted_ok_get(ppcnt_pl);
   1113	mac_stats->OctetsReceivedOK =
   1114		mlxsw_reg_ppcnt_a_octets_received_ok_get(ppcnt_pl);
   1115	mac_stats->MulticastFramesXmittedOK =
   1116		mlxsw_reg_ppcnt_a_multicast_frames_xmitted_ok_get(ppcnt_pl);
   1117	mac_stats->BroadcastFramesXmittedOK =
   1118		mlxsw_reg_ppcnt_a_broadcast_frames_xmitted_ok_get(ppcnt_pl);
   1119	mac_stats->MulticastFramesReceivedOK =
   1120		mlxsw_reg_ppcnt_a_multicast_frames_received_ok_get(ppcnt_pl);
   1121	mac_stats->BroadcastFramesReceivedOK =
   1122		mlxsw_reg_ppcnt_a_broadcast_frames_received_ok_get(ppcnt_pl);
   1123	mac_stats->InRangeLengthErrors =
   1124		mlxsw_reg_ppcnt_a_in_range_length_errors_get(ppcnt_pl);
   1125	mac_stats->OutOfRangeLengthField =
   1126		mlxsw_reg_ppcnt_a_out_of_range_length_field_get(ppcnt_pl);
   1127	mac_stats->FrameTooLongErrors =
   1128		mlxsw_reg_ppcnt_a_frame_too_long_errors_get(ppcnt_pl);
   1129}
   1130
   1131static void
   1132mlxsw_sp_get_eth_ctrl_stats(struct net_device *dev,
   1133			    struct ethtool_eth_ctrl_stats *ctrl_stats)
   1134{
   1135	char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
   1136
   1137	if (mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT,
   1138					0, ppcnt_pl))
   1139		return;
   1140
   1141	ctrl_stats->MACControlFramesTransmitted =
   1142		mlxsw_reg_ppcnt_a_mac_control_frames_transmitted_get(ppcnt_pl);
   1143	ctrl_stats->MACControlFramesReceived =
   1144		mlxsw_reg_ppcnt_a_mac_control_frames_received_get(ppcnt_pl);
   1145	ctrl_stats->UnsupportedOpcodesReceived =
   1146		mlxsw_reg_ppcnt_a_unsupported_opcodes_received_get(ppcnt_pl);
   1147}
   1148
   1149static const struct ethtool_rmon_hist_range mlxsw_rmon_ranges[] = {
   1150	{    0,    64 },
   1151	{   65,   127 },
   1152	{  128,   255 },
   1153	{  256,   511 },
   1154	{  512,  1023 },
   1155	{ 1024,  1518 },
   1156	{ 1519,  2047 },
   1157	{ 2048,  4095 },
   1158	{ 4096,  8191 },
   1159	{ 8192, 10239 },
   1160	{}
   1161};
   1162
   1163static void
   1164mlxsw_sp_get_rmon_stats(struct net_device *dev,
   1165			struct ethtool_rmon_stats *rmon,
   1166			const struct ethtool_rmon_hist_range **ranges)
   1167{
   1168	char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
   1169
   1170	if (mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_RFC_2819_CNT,
   1171					0, ppcnt_pl))
   1172		return;
   1173
   1174	rmon->undersize_pkts =
   1175		mlxsw_reg_ppcnt_ether_stats_undersize_pkts_get(ppcnt_pl);
   1176	rmon->oversize_pkts =
   1177		mlxsw_reg_ppcnt_ether_stats_oversize_pkts_get(ppcnt_pl);
   1178	rmon->fragments =
   1179		mlxsw_reg_ppcnt_ether_stats_fragments_get(ppcnt_pl);
   1180
   1181	rmon->hist[0] = mlxsw_reg_ppcnt_ether_stats_pkts64octets_get(ppcnt_pl);
   1182	rmon->hist[1] =
   1183		mlxsw_reg_ppcnt_ether_stats_pkts65to127octets_get(ppcnt_pl);
   1184	rmon->hist[2] =
   1185		mlxsw_reg_ppcnt_ether_stats_pkts128to255octets_get(ppcnt_pl);
   1186	rmon->hist[3] =
   1187		mlxsw_reg_ppcnt_ether_stats_pkts256to511octets_get(ppcnt_pl);
   1188	rmon->hist[4] =
   1189		mlxsw_reg_ppcnt_ether_stats_pkts512to1023octets_get(ppcnt_pl);
   1190	rmon->hist[5] =
   1191		mlxsw_reg_ppcnt_ether_stats_pkts1024to1518octets_get(ppcnt_pl);
   1192	rmon->hist[6] =
   1193		mlxsw_reg_ppcnt_ether_stats_pkts1519to2047octets_get(ppcnt_pl);
   1194	rmon->hist[7] =
   1195		mlxsw_reg_ppcnt_ether_stats_pkts2048to4095octets_get(ppcnt_pl);
   1196	rmon->hist[8] =
   1197		mlxsw_reg_ppcnt_ether_stats_pkts4096to8191octets_get(ppcnt_pl);
   1198	rmon->hist[9] =
   1199		mlxsw_reg_ppcnt_ether_stats_pkts8192to10239octets_get(ppcnt_pl);
   1200
   1201	*ranges = mlxsw_rmon_ranges;
   1202}
   1203
   1204static int mlxsw_sp_reset(struct net_device *dev, u32 *flags)
   1205{
   1206	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
   1207	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
   1208	u8 slot_index = mlxsw_sp_port->mapping.slot_index;
   1209	u8 module = mlxsw_sp_port->mapping.module;
   1210
   1211	return mlxsw_env_reset_module(dev, mlxsw_sp->core, slot_index,
   1212				      module, flags);
   1213}
   1214
   1215static int
   1216mlxsw_sp_get_module_power_mode(struct net_device *dev,
   1217			       struct ethtool_module_power_mode_params *params,
   1218			       struct netlink_ext_ack *extack)
   1219{
   1220	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
   1221	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
   1222	u8 slot_index = mlxsw_sp_port->mapping.slot_index;
   1223	u8 module = mlxsw_sp_port->mapping.module;
   1224
   1225	return mlxsw_env_get_module_power_mode(mlxsw_sp->core, slot_index,
   1226					       module, params, extack);
   1227}
   1228
   1229static int
   1230mlxsw_sp_set_module_power_mode(struct net_device *dev,
   1231			       const struct ethtool_module_power_mode_params *params,
   1232			       struct netlink_ext_ack *extack)
   1233{
   1234	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
   1235	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
   1236	u8 slot_index = mlxsw_sp_port->mapping.slot_index;
   1237	u8 module = mlxsw_sp_port->mapping.module;
   1238
   1239	return mlxsw_env_set_module_power_mode(mlxsw_sp->core, slot_index,
   1240					       module, params->policy, extack);
   1241}
   1242
   1243const struct ethtool_ops mlxsw_sp_port_ethtool_ops = {
   1244	.cap_link_lanes_supported	= true,
   1245	.get_drvinfo			= mlxsw_sp_port_get_drvinfo,
   1246	.get_link			= ethtool_op_get_link,
   1247	.get_link_ext_state		= mlxsw_sp_port_get_link_ext_state,
   1248	.get_pauseparam			= mlxsw_sp_port_get_pauseparam,
   1249	.set_pauseparam			= mlxsw_sp_port_set_pauseparam,
   1250	.get_strings			= mlxsw_sp_port_get_strings,
   1251	.set_phys_id			= mlxsw_sp_port_set_phys_id,
   1252	.get_ethtool_stats		= mlxsw_sp_port_get_stats,
   1253	.get_sset_count			= mlxsw_sp_port_get_sset_count,
   1254	.get_link_ksettings		= mlxsw_sp_port_get_link_ksettings,
   1255	.set_link_ksettings		= mlxsw_sp_port_set_link_ksettings,
   1256	.get_module_info		= mlxsw_sp_get_module_info,
   1257	.get_module_eeprom		= mlxsw_sp_get_module_eeprom,
   1258	.get_module_eeprom_by_page	= mlxsw_sp_get_module_eeprom_by_page,
   1259	.get_ts_info			= mlxsw_sp_get_ts_info,
   1260	.get_eth_phy_stats		= mlxsw_sp_get_eth_phy_stats,
   1261	.get_eth_mac_stats		= mlxsw_sp_get_eth_mac_stats,
   1262	.get_eth_ctrl_stats		= mlxsw_sp_get_eth_ctrl_stats,
   1263	.get_rmon_stats			= mlxsw_sp_get_rmon_stats,
   1264	.reset				= mlxsw_sp_reset,
   1265	.get_module_power_mode		= mlxsw_sp_get_module_power_mode,
   1266	.set_module_power_mode		= mlxsw_sp_set_module_power_mode,
   1267};
   1268
   1269struct mlxsw_sp1_port_link_mode {
   1270	enum ethtool_link_mode_bit_indices mask_ethtool;
   1271	u32 mask;
   1272	u32 speed;
   1273};
   1274
   1275static const struct mlxsw_sp1_port_link_mode mlxsw_sp1_port_link_mode[] = {
   1276	{
   1277		.mask		= MLXSW_REG_PTYS_ETH_SPEED_100BASE_T,
   1278		.mask_ethtool	= ETHTOOL_LINK_MODE_100baseT_Full_BIT,
   1279		.speed		= SPEED_100,
   1280	},
   1281	{
   1282		.mask		= MLXSW_REG_PTYS_ETH_SPEED_SGMII |
   1283				  MLXSW_REG_PTYS_ETH_SPEED_1000BASE_KX,
   1284		.mask_ethtool	= ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
   1285		.speed		= SPEED_1000,
   1286	},
   1287	{
   1288		.mask		= MLXSW_REG_PTYS_ETH_SPEED_1000BASE_T,
   1289		.mask_ethtool   = ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
   1290		.speed          = SPEED_1000,
   1291	},
   1292	{
   1293		.mask		= MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CX4 |
   1294				  MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4,
   1295		.mask_ethtool	= ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
   1296		.speed		= SPEED_10000,
   1297	},
   1298	{
   1299		.mask		= MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR |
   1300				  MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR |
   1301				  MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR |
   1302				  MLXSW_REG_PTYS_ETH_SPEED_10GBASE_ER_LR,
   1303		.mask_ethtool	= ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
   1304		.speed		= SPEED_10000,
   1305	},
   1306	{
   1307		.mask		= MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4,
   1308		.mask_ethtool	= ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
   1309		.speed		= SPEED_40000,
   1310	},
   1311	{
   1312		.mask		= MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4,
   1313		.mask_ethtool	= ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
   1314		.speed		= SPEED_40000,
   1315	},
   1316	{
   1317		.mask		= MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4,
   1318		.mask_ethtool	= ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
   1319		.speed		= SPEED_40000,
   1320	},
   1321	{
   1322		.mask		= MLXSW_REG_PTYS_ETH_SPEED_40GBASE_LR4_ER4,
   1323		.mask_ethtool	= ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
   1324		.speed		= SPEED_40000,
   1325	},
   1326	{
   1327		.mask		= MLXSW_REG_PTYS_ETH_SPEED_25GBASE_CR,
   1328		.mask_ethtool	= ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
   1329		.speed		= SPEED_25000,
   1330	},
   1331	{
   1332		.mask		= MLXSW_REG_PTYS_ETH_SPEED_25GBASE_KR,
   1333		.mask_ethtool	= ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
   1334		.speed		= SPEED_25000,
   1335	},
   1336	{
   1337		.mask		= MLXSW_REG_PTYS_ETH_SPEED_25GBASE_SR,
   1338		.mask_ethtool	= ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
   1339		.speed		= SPEED_25000,
   1340	},
   1341	{
   1342		.mask		= MLXSW_REG_PTYS_ETH_SPEED_50GBASE_CR2,
   1343		.mask_ethtool	= ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
   1344		.speed		= SPEED_50000,
   1345	},
   1346	{
   1347		.mask		= MLXSW_REG_PTYS_ETH_SPEED_50GBASE_KR2,
   1348		.mask_ethtool	= ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
   1349		.speed		= SPEED_50000,
   1350	},
   1351	{
   1352		.mask		= MLXSW_REG_PTYS_ETH_SPEED_50GBASE_SR2,
   1353		.mask_ethtool	= ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
   1354		.speed		= SPEED_50000,
   1355	},
   1356	{
   1357		.mask		= MLXSW_REG_PTYS_ETH_SPEED_100GBASE_CR4,
   1358		.mask_ethtool	= ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
   1359		.speed		= SPEED_100000,
   1360	},
   1361	{
   1362		.mask		= MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4,
   1363		.mask_ethtool	= ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
   1364		.speed		= SPEED_100000,
   1365	},
   1366	{
   1367		.mask		= MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4,
   1368		.mask_ethtool	= ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
   1369		.speed		= SPEED_100000,
   1370	},
   1371	{
   1372		.mask		= MLXSW_REG_PTYS_ETH_SPEED_100GBASE_LR4_ER4,
   1373		.mask_ethtool	= ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
   1374		.speed		= SPEED_100000,
   1375	},
   1376};
   1377
   1378#define MLXSW_SP1_PORT_LINK_MODE_LEN ARRAY_SIZE(mlxsw_sp1_port_link_mode)
   1379
   1380static void
   1381mlxsw_sp1_from_ptys_supported_port(struct mlxsw_sp *mlxsw_sp,
   1382				   u32 ptys_eth_proto,
   1383				   struct ethtool_link_ksettings *cmd)
   1384{
   1385	if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR |
   1386			      MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR |
   1387			      MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4 |
   1388			      MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4 |
   1389			      MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4 |
   1390			      MLXSW_REG_PTYS_ETH_SPEED_SGMII))
   1391		ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
   1392
   1393	if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR |
   1394			      MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4 |
   1395			      MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4 |
   1396			      MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4 |
   1397			      MLXSW_REG_PTYS_ETH_SPEED_1000BASE_KX))
   1398		ethtool_link_ksettings_add_link_mode(cmd, supported, Backplane);
   1399}
   1400
   1401static void
   1402mlxsw_sp1_from_ptys_link(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto,
   1403			 unsigned long *mode)
   1404{
   1405	int i;
   1406
   1407	for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
   1408		if (ptys_eth_proto & mlxsw_sp1_port_link_mode[i].mask)
   1409			__set_bit(mlxsw_sp1_port_link_mode[i].mask_ethtool,
   1410				  mode);
   1411	}
   1412}
   1413
   1414static u32
   1415mlxsw_sp1_from_ptys_speed(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto)
   1416{
   1417	int i;
   1418
   1419	for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
   1420		if (ptys_eth_proto & mlxsw_sp1_port_link_mode[i].mask)
   1421			return mlxsw_sp1_port_link_mode[i].speed;
   1422	}
   1423
   1424	return SPEED_UNKNOWN;
   1425}
   1426
   1427static void
   1428mlxsw_sp1_from_ptys_link_mode(struct mlxsw_sp *mlxsw_sp, bool carrier_ok,
   1429			      u32 ptys_eth_proto,
   1430			      struct ethtool_link_ksettings *cmd)
   1431{
   1432	struct mlxsw_sp1_port_link_mode link;
   1433	int i;
   1434
   1435	cmd->base.speed = SPEED_UNKNOWN;
   1436	cmd->base.duplex = DUPLEX_UNKNOWN;
   1437	cmd->lanes = 0;
   1438
   1439	if (!carrier_ok)
   1440		return;
   1441
   1442	for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
   1443		if (ptys_eth_proto & mlxsw_sp1_port_link_mode[i].mask) {
   1444			link = mlxsw_sp1_port_link_mode[i];
   1445			ethtool_params_from_link_mode(cmd,
   1446						      link.mask_ethtool);
   1447		}
   1448	}
   1449}
   1450
   1451static int mlxsw_sp1_ptys_max_speed(struct mlxsw_sp_port *mlxsw_sp_port, u32 *p_max_speed)
   1452{
   1453	u32 eth_proto_cap;
   1454	u32 max_speed = 0;
   1455	int err;
   1456	int i;
   1457
   1458	err = mlxsw_sp_port_ptys_query(mlxsw_sp_port, &eth_proto_cap, NULL, NULL, NULL);
   1459	if (err)
   1460		return err;
   1461
   1462	for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
   1463		if ((eth_proto_cap & mlxsw_sp1_port_link_mode[i].mask) &&
   1464		    mlxsw_sp1_port_link_mode[i].speed > max_speed)
   1465			max_speed = mlxsw_sp1_port_link_mode[i].speed;
   1466	}
   1467
   1468	*p_max_speed = max_speed;
   1469	return 0;
   1470}
   1471
   1472static u32
   1473mlxsw_sp1_to_ptys_advert_link(struct mlxsw_sp *mlxsw_sp,
   1474			      const struct ethtool_link_ksettings *cmd)
   1475{
   1476	u32 ptys_proto = 0;
   1477	int i;
   1478
   1479	for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
   1480		if (test_bit(mlxsw_sp1_port_link_mode[i].mask_ethtool,
   1481			     cmd->link_modes.advertising))
   1482			ptys_proto |= mlxsw_sp1_port_link_mode[i].mask;
   1483	}
   1484	return ptys_proto;
   1485}
   1486
   1487static u32 mlxsw_sp1_to_ptys_speed_lanes(struct mlxsw_sp *mlxsw_sp, u8 width,
   1488					 const struct ethtool_link_ksettings *cmd)
   1489{
   1490	u32 ptys_proto = 0;
   1491	int i;
   1492
   1493	if (cmd->lanes > width)
   1494		return ptys_proto;
   1495
   1496	for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
   1497		if (cmd->base.speed == mlxsw_sp1_port_link_mode[i].speed)
   1498			ptys_proto |= mlxsw_sp1_port_link_mode[i].mask;
   1499	}
   1500	return ptys_proto;
   1501}
   1502
   1503static void
   1504mlxsw_sp1_reg_ptys_eth_pack(struct mlxsw_sp *mlxsw_sp, char *payload,
   1505			    u16 local_port, u32 proto_admin, bool autoneg)
   1506{
   1507	mlxsw_reg_ptys_eth_pack(payload, local_port, proto_admin, autoneg);
   1508}
   1509
   1510static void
   1511mlxsw_sp1_reg_ptys_eth_unpack(struct mlxsw_sp *mlxsw_sp, char *payload,
   1512			      u32 *p_eth_proto_cap, u32 *p_eth_proto_admin,
   1513			      u32 *p_eth_proto_oper)
   1514{
   1515	mlxsw_reg_ptys_eth_unpack(payload, p_eth_proto_cap, p_eth_proto_admin,
   1516				  p_eth_proto_oper);
   1517}
   1518
   1519static u32 mlxsw_sp1_ptys_proto_cap_masked_get(u32 eth_proto_cap)
   1520{
   1521	u32 ptys_proto_cap_masked = 0;
   1522	int i;
   1523
   1524	for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
   1525		if (mlxsw_sp1_port_link_mode[i].mask & eth_proto_cap)
   1526			ptys_proto_cap_masked |=
   1527				mlxsw_sp1_port_link_mode[i].mask;
   1528	}
   1529
   1530	return ptys_proto_cap_masked;
   1531}
   1532
   1533const struct mlxsw_sp_port_type_speed_ops mlxsw_sp1_port_type_speed_ops = {
   1534	.from_ptys_supported_port	= mlxsw_sp1_from_ptys_supported_port,
   1535	.from_ptys_link			= mlxsw_sp1_from_ptys_link,
   1536	.from_ptys_speed		= mlxsw_sp1_from_ptys_speed,
   1537	.from_ptys_link_mode		= mlxsw_sp1_from_ptys_link_mode,
   1538	.ptys_max_speed			= mlxsw_sp1_ptys_max_speed,
   1539	.to_ptys_advert_link		= mlxsw_sp1_to_ptys_advert_link,
   1540	.to_ptys_speed_lanes		= mlxsw_sp1_to_ptys_speed_lanes,
   1541	.reg_ptys_eth_pack		= mlxsw_sp1_reg_ptys_eth_pack,
   1542	.reg_ptys_eth_unpack		= mlxsw_sp1_reg_ptys_eth_unpack,
   1543	.ptys_proto_cap_masked_get	= mlxsw_sp1_ptys_proto_cap_masked_get,
   1544};
   1545
   1546static const enum ethtool_link_mode_bit_indices
   1547mlxsw_sp2_mask_ethtool_sgmii_100m[] = {
   1548	ETHTOOL_LINK_MODE_100baseT_Full_BIT,
   1549};
   1550
   1551#define MLXSW_SP2_MASK_ETHTOOL_SGMII_100M_LEN \
   1552	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_sgmii_100m)
   1553
   1554static const enum ethtool_link_mode_bit_indices
   1555mlxsw_sp2_mask_ethtool_1000base_x_sgmii[] = {
   1556	ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
   1557	ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
   1558};
   1559
   1560#define MLXSW_SP2_MASK_ETHTOOL_1000BASE_X_SGMII_LEN \
   1561	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_1000base_x_sgmii)
   1562
   1563static const enum ethtool_link_mode_bit_indices
   1564mlxsw_sp2_mask_ethtool_5gbase_r[] = {
   1565	ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
   1566};
   1567
   1568#define MLXSW_SP2_MASK_ETHTOOL_5GBASE_R_LEN \
   1569	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_5gbase_r)
   1570
   1571static const enum ethtool_link_mode_bit_indices
   1572mlxsw_sp2_mask_ethtool_xfi_xaui_1_10g[] = {
   1573	ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
   1574	ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
   1575	ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
   1576	ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
   1577	ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
   1578	ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
   1579	ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
   1580};
   1581
   1582#define MLXSW_SP2_MASK_ETHTOOL_XFI_XAUI_1_10G_LEN \
   1583	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_xfi_xaui_1_10g)
   1584
   1585static const enum ethtool_link_mode_bit_indices
   1586mlxsw_sp2_mask_ethtool_xlaui_4_xlppi_4_40g[] = {
   1587	ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
   1588	ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
   1589	ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
   1590	ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
   1591};
   1592
   1593#define MLXSW_SP2_MASK_ETHTOOL_XLAUI_4_XLPPI_4_40G_LEN \
   1594	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_xlaui_4_xlppi_4_40g)
   1595
   1596static const enum ethtool_link_mode_bit_indices
   1597mlxsw_sp2_mask_ethtool_25gaui_1_25gbase_cr_kr[] = {
   1598	ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
   1599	ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
   1600	ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
   1601};
   1602
   1603#define MLXSW_SP2_MASK_ETHTOOL_25GAUI_1_25GBASE_CR_KR_LEN \
   1604	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_25gaui_1_25gbase_cr_kr)
   1605
   1606static const enum ethtool_link_mode_bit_indices
   1607mlxsw_sp2_mask_ethtool_50gaui_2_laui_2_50gbase_cr2_kr2[] = {
   1608	ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
   1609	ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
   1610	ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
   1611};
   1612
   1613#define MLXSW_SP2_MASK_ETHTOOL_50GAUI_2_LAUI_2_50GBASE_CR2_KR2_LEN \
   1614	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_50gaui_2_laui_2_50gbase_cr2_kr2)
   1615
   1616static const enum ethtool_link_mode_bit_indices
   1617mlxsw_sp2_mask_ethtool_50gaui_1_laui_1_50gbase_cr_kr[] = {
   1618	ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
   1619	ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
   1620	ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
   1621	ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
   1622	ETHTOOL_LINK_MODE_50000baseDR_Full_BIT,
   1623};
   1624
   1625#define MLXSW_SP2_MASK_ETHTOOL_50GAUI_1_LAUI_1_50GBASE_CR_KR_LEN \
   1626	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_50gaui_1_laui_1_50gbase_cr_kr)
   1627
   1628static const enum ethtool_link_mode_bit_indices
   1629mlxsw_sp2_mask_ethtool_caui_4_100gbase_cr4_kr4[] = {
   1630	ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
   1631	ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
   1632	ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
   1633	ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
   1634};
   1635
   1636#define MLXSW_SP2_MASK_ETHTOOL_CAUI_4_100GBASE_CR4_KR4_LEN \
   1637	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_caui_4_100gbase_cr4_kr4)
   1638
   1639static const enum ethtool_link_mode_bit_indices
   1640mlxsw_sp2_mask_ethtool_100gaui_2_100gbase_cr2_kr2[] = {
   1641	ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT,
   1642	ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT,
   1643	ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT,
   1644	ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
   1645	ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT,
   1646};
   1647
   1648#define MLXSW_SP2_MASK_ETHTOOL_100GAUI_2_100GBASE_CR2_KR2_LEN \
   1649	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_100gaui_2_100gbase_cr2_kr2)
   1650
   1651static const enum ethtool_link_mode_bit_indices
   1652mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4[] = {
   1653	ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT,
   1654	ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT,
   1655	ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT,
   1656	ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT,
   1657	ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT,
   1658};
   1659
   1660#define MLXSW_SP2_MASK_ETHTOOL_200GAUI_4_200GBASE_CR4_KR4_LEN \
   1661	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4)
   1662
   1663static const enum ethtool_link_mode_bit_indices
   1664mlxsw_sp2_mask_ethtool_400gaui_8[] = {
   1665	ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT,
   1666	ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT,
   1667	ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT,
   1668	ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT,
   1669	ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT,
   1670};
   1671
   1672#define MLXSW_SP2_MASK_ETHTOOL_400GAUI_8_LEN \
   1673	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_400gaui_8)
   1674
   1675#define MLXSW_SP_PORT_MASK_WIDTH_1X	BIT(0)
   1676#define MLXSW_SP_PORT_MASK_WIDTH_2X	BIT(1)
   1677#define MLXSW_SP_PORT_MASK_WIDTH_4X	BIT(2)
   1678#define MLXSW_SP_PORT_MASK_WIDTH_8X	BIT(3)
   1679
   1680static u8 mlxsw_sp_port_mask_width_get(u8 width)
   1681{
   1682	switch (width) {
   1683	case 1:
   1684		return MLXSW_SP_PORT_MASK_WIDTH_1X;
   1685	case 2:
   1686		return MLXSW_SP_PORT_MASK_WIDTH_2X;
   1687	case 4:
   1688		return MLXSW_SP_PORT_MASK_WIDTH_4X;
   1689	case 8:
   1690		return MLXSW_SP_PORT_MASK_WIDTH_8X;
   1691	default:
   1692		WARN_ON_ONCE(1);
   1693		return 0;
   1694	}
   1695}
   1696
   1697struct mlxsw_sp2_port_link_mode {
   1698	const enum ethtool_link_mode_bit_indices *mask_ethtool;
   1699	int m_ethtool_len;
   1700	u32 mask;
   1701	u32 speed;
   1702	u32 width;
   1703	u8 mask_sup_width;
   1704};
   1705
   1706static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = {
   1707	{
   1708		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_SGMII_100M,
   1709		.mask_ethtool	= mlxsw_sp2_mask_ethtool_sgmii_100m,
   1710		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_SGMII_100M_LEN,
   1711		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_1X |
   1712				  MLXSW_SP_PORT_MASK_WIDTH_2X |
   1713				  MLXSW_SP_PORT_MASK_WIDTH_4X |
   1714				  MLXSW_SP_PORT_MASK_WIDTH_8X,
   1715		.speed		= SPEED_100,
   1716		.width		= 1,
   1717	},
   1718	{
   1719		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_1000BASE_X_SGMII,
   1720		.mask_ethtool	= mlxsw_sp2_mask_ethtool_1000base_x_sgmii,
   1721		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_1000BASE_X_SGMII_LEN,
   1722		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_1X |
   1723				  MLXSW_SP_PORT_MASK_WIDTH_2X |
   1724				  MLXSW_SP_PORT_MASK_WIDTH_4X |
   1725				  MLXSW_SP_PORT_MASK_WIDTH_8X,
   1726		.speed		= SPEED_1000,
   1727		.width		= 1,
   1728	},
   1729	{
   1730		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_5GBASE_R,
   1731		.mask_ethtool	= mlxsw_sp2_mask_ethtool_5gbase_r,
   1732		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_5GBASE_R_LEN,
   1733		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_1X |
   1734				  MLXSW_SP_PORT_MASK_WIDTH_2X |
   1735				  MLXSW_SP_PORT_MASK_WIDTH_4X |
   1736				  MLXSW_SP_PORT_MASK_WIDTH_8X,
   1737		.speed		= SPEED_5000,
   1738		.width		= 1,
   1739	},
   1740	{
   1741		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_XFI_XAUI_1_10G,
   1742		.mask_ethtool	= mlxsw_sp2_mask_ethtool_xfi_xaui_1_10g,
   1743		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_XFI_XAUI_1_10G_LEN,
   1744		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_1X |
   1745				  MLXSW_SP_PORT_MASK_WIDTH_2X |
   1746				  MLXSW_SP_PORT_MASK_WIDTH_4X |
   1747				  MLXSW_SP_PORT_MASK_WIDTH_8X,
   1748		.speed		= SPEED_10000,
   1749		.width		= 1,
   1750	},
   1751	{
   1752		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_XLAUI_4_XLPPI_4_40G,
   1753		.mask_ethtool	= mlxsw_sp2_mask_ethtool_xlaui_4_xlppi_4_40g,
   1754		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_XLAUI_4_XLPPI_4_40G_LEN,
   1755		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_4X |
   1756				  MLXSW_SP_PORT_MASK_WIDTH_8X,
   1757		.speed		= SPEED_40000,
   1758		.width		= 4,
   1759	},
   1760	{
   1761		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_25GAUI_1_25GBASE_CR_KR,
   1762		.mask_ethtool	= mlxsw_sp2_mask_ethtool_25gaui_1_25gbase_cr_kr,
   1763		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_25GAUI_1_25GBASE_CR_KR_LEN,
   1764		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_1X |
   1765				  MLXSW_SP_PORT_MASK_WIDTH_2X |
   1766				  MLXSW_SP_PORT_MASK_WIDTH_4X |
   1767				  MLXSW_SP_PORT_MASK_WIDTH_8X,
   1768		.speed		= SPEED_25000,
   1769		.width		= 1,
   1770	},
   1771	{
   1772		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_50GAUI_2_LAUI_2_50GBASE_CR2_KR2,
   1773		.mask_ethtool	= mlxsw_sp2_mask_ethtool_50gaui_2_laui_2_50gbase_cr2_kr2,
   1774		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_50GAUI_2_LAUI_2_50GBASE_CR2_KR2_LEN,
   1775		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_2X |
   1776				  MLXSW_SP_PORT_MASK_WIDTH_4X |
   1777				  MLXSW_SP_PORT_MASK_WIDTH_8X,
   1778		.speed		= SPEED_50000,
   1779		.width		= 2,
   1780	},
   1781	{
   1782		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_50GAUI_1_LAUI_1_50GBASE_CR_KR,
   1783		.mask_ethtool	= mlxsw_sp2_mask_ethtool_50gaui_1_laui_1_50gbase_cr_kr,
   1784		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_50GAUI_1_LAUI_1_50GBASE_CR_KR_LEN,
   1785		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_1X,
   1786		.speed		= SPEED_50000,
   1787		.width		= 1,
   1788	},
   1789	{
   1790		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_CAUI_4_100GBASE_CR4_KR4,
   1791		.mask_ethtool	= mlxsw_sp2_mask_ethtool_caui_4_100gbase_cr4_kr4,
   1792		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_CAUI_4_100GBASE_CR4_KR4_LEN,
   1793		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_4X |
   1794				  MLXSW_SP_PORT_MASK_WIDTH_8X,
   1795		.speed		= SPEED_100000,
   1796		.width		= 4,
   1797	},
   1798	{
   1799		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_100GAUI_2_100GBASE_CR2_KR2,
   1800		.mask_ethtool	= mlxsw_sp2_mask_ethtool_100gaui_2_100gbase_cr2_kr2,
   1801		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_100GAUI_2_100GBASE_CR2_KR2_LEN,
   1802		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_2X,
   1803		.speed		= SPEED_100000,
   1804		.width		= 2,
   1805	},
   1806	{
   1807		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_200GAUI_4_200GBASE_CR4_KR4,
   1808		.mask_ethtool	= mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4,
   1809		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_200GAUI_4_200GBASE_CR4_KR4_LEN,
   1810		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_4X |
   1811				  MLXSW_SP_PORT_MASK_WIDTH_8X,
   1812		.speed		= SPEED_200000,
   1813		.width		= 4,
   1814	},
   1815	{
   1816		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_400GAUI_8,
   1817		.mask_ethtool	= mlxsw_sp2_mask_ethtool_400gaui_8,
   1818		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_400GAUI_8_LEN,
   1819		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_8X,
   1820		.speed		= SPEED_400000,
   1821		.width		= 8,
   1822	},
   1823};
   1824
   1825#define MLXSW_SP2_PORT_LINK_MODE_LEN ARRAY_SIZE(mlxsw_sp2_port_link_mode)
   1826
   1827static void
   1828mlxsw_sp2_from_ptys_supported_port(struct mlxsw_sp *mlxsw_sp,
   1829				   u32 ptys_eth_proto,
   1830				   struct ethtool_link_ksettings *cmd)
   1831{
   1832	ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
   1833	ethtool_link_ksettings_add_link_mode(cmd, supported, Backplane);
   1834}
   1835
   1836static void
   1837mlxsw_sp2_set_bit_ethtool(const struct mlxsw_sp2_port_link_mode *link_mode,
   1838			  unsigned long *mode)
   1839{
   1840	int i;
   1841
   1842	for (i = 0; i < link_mode->m_ethtool_len; i++)
   1843		__set_bit(link_mode->mask_ethtool[i], mode);
   1844}
   1845
   1846static void
   1847mlxsw_sp2_from_ptys_link(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto,
   1848			 unsigned long *mode)
   1849{
   1850	int i;
   1851
   1852	for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
   1853		if (ptys_eth_proto & mlxsw_sp2_port_link_mode[i].mask)
   1854			mlxsw_sp2_set_bit_ethtool(&mlxsw_sp2_port_link_mode[i],
   1855						  mode);
   1856	}
   1857}
   1858
   1859static u32
   1860mlxsw_sp2_from_ptys_speed(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto)
   1861{
   1862	int i;
   1863
   1864	for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
   1865		if (ptys_eth_proto & mlxsw_sp2_port_link_mode[i].mask)
   1866			return mlxsw_sp2_port_link_mode[i].speed;
   1867	}
   1868
   1869	return SPEED_UNKNOWN;
   1870}
   1871
   1872static void
   1873mlxsw_sp2_from_ptys_link_mode(struct mlxsw_sp *mlxsw_sp, bool carrier_ok,
   1874			      u32 ptys_eth_proto,
   1875			      struct ethtool_link_ksettings *cmd)
   1876{
   1877	struct mlxsw_sp2_port_link_mode link;
   1878	int i;
   1879
   1880	cmd->base.speed = SPEED_UNKNOWN;
   1881	cmd->base.duplex = DUPLEX_UNKNOWN;
   1882	cmd->lanes = 0;
   1883
   1884	if (!carrier_ok)
   1885		return;
   1886
   1887	for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
   1888		if (ptys_eth_proto & mlxsw_sp2_port_link_mode[i].mask) {
   1889			link = mlxsw_sp2_port_link_mode[i];
   1890			ethtool_params_from_link_mode(cmd,
   1891						      link.mask_ethtool[1]);
   1892		}
   1893	}
   1894}
   1895
   1896static int mlxsw_sp2_ptys_max_speed(struct mlxsw_sp_port *mlxsw_sp_port, u32 *p_max_speed)
   1897{
   1898	u32 eth_proto_cap;
   1899	u32 max_speed = 0;
   1900	int err;
   1901	int i;
   1902
   1903	err = mlxsw_sp_port_ptys_query(mlxsw_sp_port, &eth_proto_cap, NULL, NULL, NULL);
   1904	if (err)
   1905		return err;
   1906
   1907	for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
   1908		if ((eth_proto_cap & mlxsw_sp2_port_link_mode[i].mask) &&
   1909		    mlxsw_sp2_port_link_mode[i].speed > max_speed)
   1910			max_speed = mlxsw_sp2_port_link_mode[i].speed;
   1911	}
   1912
   1913	*p_max_speed = max_speed;
   1914	return 0;
   1915}
   1916
   1917static bool
   1918mlxsw_sp2_test_bit_ethtool(const struct mlxsw_sp2_port_link_mode *link_mode,
   1919			   const unsigned long *mode)
   1920{
   1921	int cnt = 0;
   1922	int i;
   1923
   1924	for (i = 0; i < link_mode->m_ethtool_len; i++) {
   1925		if (test_bit(link_mode->mask_ethtool[i], mode))
   1926			cnt++;
   1927	}
   1928
   1929	return cnt == link_mode->m_ethtool_len;
   1930}
   1931
   1932static u32
   1933mlxsw_sp2_to_ptys_advert_link(struct mlxsw_sp *mlxsw_sp,
   1934			      const struct ethtool_link_ksettings *cmd)
   1935{
   1936	u32 ptys_proto = 0;
   1937	int i;
   1938
   1939	for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
   1940		if (mlxsw_sp2_test_bit_ethtool(&mlxsw_sp2_port_link_mode[i],
   1941					       cmd->link_modes.advertising))
   1942			ptys_proto |= mlxsw_sp2_port_link_mode[i].mask;
   1943	}
   1944	return ptys_proto;
   1945}
   1946
   1947static u32 mlxsw_sp2_to_ptys_speed_lanes(struct mlxsw_sp *mlxsw_sp, u8 width,
   1948					 const struct ethtool_link_ksettings *cmd)
   1949{
   1950	u8 mask_width = mlxsw_sp_port_mask_width_get(width);
   1951	struct mlxsw_sp2_port_link_mode link_mode;
   1952	u32 ptys_proto = 0;
   1953	int i;
   1954
   1955	if (cmd->lanes > width)
   1956		return ptys_proto;
   1957
   1958	for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
   1959		if (cmd->base.speed == mlxsw_sp2_port_link_mode[i].speed) {
   1960			link_mode = mlxsw_sp2_port_link_mode[i];
   1961
   1962			if (!cmd->lanes) {
   1963				/* If number of lanes was not set by user space,
   1964				 * choose the link mode that supports the width
   1965				 * of the port.
   1966				 */
   1967				if (mask_width & link_mode.mask_sup_width)
   1968					ptys_proto |= link_mode.mask;
   1969			} else if (cmd->lanes == link_mode.width) {
   1970				/* Else if the number of lanes was set, choose
   1971				 * the link mode that its actual width equals to
   1972				 * it.
   1973				 */
   1974				ptys_proto |= link_mode.mask;
   1975			}
   1976		}
   1977	}
   1978	return ptys_proto;
   1979}
   1980
   1981static void
   1982mlxsw_sp2_reg_ptys_eth_pack(struct mlxsw_sp *mlxsw_sp, char *payload,
   1983			    u16 local_port, u32 proto_admin,
   1984			    bool autoneg)
   1985{
   1986	mlxsw_reg_ptys_ext_eth_pack(payload, local_port, proto_admin, autoneg);
   1987}
   1988
   1989static void
   1990mlxsw_sp2_reg_ptys_eth_unpack(struct mlxsw_sp *mlxsw_sp, char *payload,
   1991			      u32 *p_eth_proto_cap, u32 *p_eth_proto_admin,
   1992			      u32 *p_eth_proto_oper)
   1993{
   1994	mlxsw_reg_ptys_ext_eth_unpack(payload, p_eth_proto_cap,
   1995				      p_eth_proto_admin, p_eth_proto_oper);
   1996}
   1997
   1998static u32 mlxsw_sp2_ptys_proto_cap_masked_get(u32 eth_proto_cap)
   1999{
   2000	u32 ptys_proto_cap_masked = 0;
   2001	int i;
   2002
   2003	for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
   2004		if (mlxsw_sp2_port_link_mode[i].mask & eth_proto_cap)
   2005			ptys_proto_cap_masked |=
   2006				mlxsw_sp2_port_link_mode[i].mask;
   2007	}
   2008
   2009	return ptys_proto_cap_masked;
   2010}
   2011
   2012const struct mlxsw_sp_port_type_speed_ops mlxsw_sp2_port_type_speed_ops = {
   2013	.from_ptys_supported_port	= mlxsw_sp2_from_ptys_supported_port,
   2014	.from_ptys_link			= mlxsw_sp2_from_ptys_link,
   2015	.from_ptys_speed		= mlxsw_sp2_from_ptys_speed,
   2016	.from_ptys_link_mode		= mlxsw_sp2_from_ptys_link_mode,
   2017	.ptys_max_speed			= mlxsw_sp2_ptys_max_speed,
   2018	.to_ptys_advert_link		= mlxsw_sp2_to_ptys_advert_link,
   2019	.to_ptys_speed_lanes		= mlxsw_sp2_to_ptys_speed_lanes,
   2020	.reg_ptys_eth_pack		= mlxsw_sp2_reg_ptys_eth_pack,
   2021	.reg_ptys_eth_unpack		= mlxsw_sp2_reg_ptys_eth_unpack,
   2022	.ptys_proto_cap_masked_get	= mlxsw_sp2_ptys_proto_cap_masked_get,
   2023};