brintos

brintos / linux-shallow public Read only

0
0
Text · 62.6 KiB · 2bed8c8 Raw
2120 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/* 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	strscpy(drvinfo->driver, mlxsw_sp->bus_info->device_kind,18		sizeof(drvinfo->driver));19	strscpy(drvinfo->version, mlxsw_sp_driver_version,20		sizeof(drvinfo->version));21	snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),22		 "%d.%d.%d",23		 mlxsw_sp->bus_info->fw_rev.major,24		 mlxsw_sp->bus_info->fw_rev.minor,25		 mlxsw_sp->bus_info->fw_rev.subminor);26	strscpy(drvinfo->bus_info, mlxsw_sp->bus_info->device_name,27		sizeof(drvinfo->bus_info));28}29 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_mapping37mlxsw_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 void105mlxsw_sp_port_set_link_ext_state(struct mlxsw_sp_ethtool_link_ext_state_opcode_mapping106				 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 int142mlxsw_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 is204 * measured in bytes. Assumes 100m cable and does not take into account MTU.205 */206#define MLXSW_SP_PAUSE_DELAY_BYTES 19476207 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	else234		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 u64569mlxsw_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, "%.28s_%d",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 int714mlxsw_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 void867mlxsw_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 void884mlxsw_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 u8901mlxsw_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 int983mlxsw_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 int1057mlxsw_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 int1071mlxsw_sp_set_module_eeprom_by_page(struct net_device *dev,1072				   const struct ethtool_module_eeprom *page,1073				   struct netlink_ext_ack *extack)1074{1075	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);1076	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;1077	u8 slot_index = mlxsw_sp_port->mapping.slot_index;1078	u8 module = mlxsw_sp_port->mapping.module;1079 1080	return mlxsw_env_set_module_eeprom_by_page(mlxsw_sp->core, slot_index,1081						   module, page, extack);1082}1083 1084static int1085mlxsw_sp_get_ts_info(struct net_device *netdev, struct kernel_ethtool_ts_info *info)1086{1087	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(netdev);1088	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;1089 1090	return mlxsw_sp->ptp_ops->get_ts_info(mlxsw_sp, info);1091}1092 1093static void1094mlxsw_sp_get_eth_phy_stats(struct net_device *dev,1095			   struct ethtool_eth_phy_stats *phy_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	phy_stats->SymbolErrorDuringCarrier =1104		mlxsw_reg_ppcnt_a_symbol_error_during_carrier_get(ppcnt_pl);1105}1106 1107static void1108mlxsw_sp_get_eth_mac_stats(struct net_device *dev,1109			   struct ethtool_eth_mac_stats *mac_stats)1110{1111	char ppcnt_pl[MLXSW_REG_PPCNT_LEN];1112 1113	if (mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT,1114					0, ppcnt_pl))1115		return;1116 1117	mac_stats->FramesTransmittedOK =1118		mlxsw_reg_ppcnt_a_frames_transmitted_ok_get(ppcnt_pl);1119	mac_stats->FramesReceivedOK =1120		mlxsw_reg_ppcnt_a_frames_received_ok_get(ppcnt_pl);1121	mac_stats->FrameCheckSequenceErrors =1122		mlxsw_reg_ppcnt_a_frame_check_sequence_errors_get(ppcnt_pl);1123	mac_stats->AlignmentErrors =1124		mlxsw_reg_ppcnt_a_alignment_errors_get(ppcnt_pl);1125	mac_stats->OctetsTransmittedOK =1126		mlxsw_reg_ppcnt_a_octets_transmitted_ok_get(ppcnt_pl);1127	mac_stats->OctetsReceivedOK =1128		mlxsw_reg_ppcnt_a_octets_received_ok_get(ppcnt_pl);1129	mac_stats->MulticastFramesXmittedOK =1130		mlxsw_reg_ppcnt_a_multicast_frames_xmitted_ok_get(ppcnt_pl);1131	mac_stats->BroadcastFramesXmittedOK =1132		mlxsw_reg_ppcnt_a_broadcast_frames_xmitted_ok_get(ppcnt_pl);1133	mac_stats->MulticastFramesReceivedOK =1134		mlxsw_reg_ppcnt_a_multicast_frames_received_ok_get(ppcnt_pl);1135	mac_stats->BroadcastFramesReceivedOK =1136		mlxsw_reg_ppcnt_a_broadcast_frames_received_ok_get(ppcnt_pl);1137	mac_stats->InRangeLengthErrors =1138		mlxsw_reg_ppcnt_a_in_range_length_errors_get(ppcnt_pl);1139	mac_stats->OutOfRangeLengthField =1140		mlxsw_reg_ppcnt_a_out_of_range_length_field_get(ppcnt_pl);1141	mac_stats->FrameTooLongErrors =1142		mlxsw_reg_ppcnt_a_frame_too_long_errors_get(ppcnt_pl);1143}1144 1145static void1146mlxsw_sp_get_eth_ctrl_stats(struct net_device *dev,1147			    struct ethtool_eth_ctrl_stats *ctrl_stats)1148{1149	char ppcnt_pl[MLXSW_REG_PPCNT_LEN];1150 1151	if (mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT,1152					0, ppcnt_pl))1153		return;1154 1155	ctrl_stats->MACControlFramesTransmitted =1156		mlxsw_reg_ppcnt_a_mac_control_frames_transmitted_get(ppcnt_pl);1157	ctrl_stats->MACControlFramesReceived =1158		mlxsw_reg_ppcnt_a_mac_control_frames_received_get(ppcnt_pl);1159	ctrl_stats->UnsupportedOpcodesReceived =1160		mlxsw_reg_ppcnt_a_unsupported_opcodes_received_get(ppcnt_pl);1161}1162 1163static const struct ethtool_rmon_hist_range mlxsw_rmon_ranges[] = {1164	{    0,    64 },1165	{   65,   127 },1166	{  128,   255 },1167	{  256,   511 },1168	{  512,  1023 },1169	{ 1024,  1518 },1170	{ 1519,  2047 },1171	{ 2048,  4095 },1172	{ 4096,  8191 },1173	{ 8192, 10239 },1174	{}1175};1176 1177static void1178mlxsw_sp_get_rmon_stats(struct net_device *dev,1179			struct ethtool_rmon_stats *rmon,1180			const struct ethtool_rmon_hist_range **ranges)1181{1182	char ppcnt_pl[MLXSW_REG_PPCNT_LEN];1183 1184	if (mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_RFC_2819_CNT,1185					0, ppcnt_pl))1186		return;1187 1188	rmon->undersize_pkts =1189		mlxsw_reg_ppcnt_ether_stats_undersize_pkts_get(ppcnt_pl);1190	rmon->oversize_pkts =1191		mlxsw_reg_ppcnt_ether_stats_oversize_pkts_get(ppcnt_pl);1192	rmon->fragments =1193		mlxsw_reg_ppcnt_ether_stats_fragments_get(ppcnt_pl);1194 1195	rmon->hist[0] = mlxsw_reg_ppcnt_ether_stats_pkts64octets_get(ppcnt_pl);1196	rmon->hist[1] =1197		mlxsw_reg_ppcnt_ether_stats_pkts65to127octets_get(ppcnt_pl);1198	rmon->hist[2] =1199		mlxsw_reg_ppcnt_ether_stats_pkts128to255octets_get(ppcnt_pl);1200	rmon->hist[3] =1201		mlxsw_reg_ppcnt_ether_stats_pkts256to511octets_get(ppcnt_pl);1202	rmon->hist[4] =1203		mlxsw_reg_ppcnt_ether_stats_pkts512to1023octets_get(ppcnt_pl);1204	rmon->hist[5] =1205		mlxsw_reg_ppcnt_ether_stats_pkts1024to1518octets_get(ppcnt_pl);1206	rmon->hist[6] =1207		mlxsw_reg_ppcnt_ether_stats_pkts1519to2047octets_get(ppcnt_pl);1208	rmon->hist[7] =1209		mlxsw_reg_ppcnt_ether_stats_pkts2048to4095octets_get(ppcnt_pl);1210	rmon->hist[8] =1211		mlxsw_reg_ppcnt_ether_stats_pkts4096to8191octets_get(ppcnt_pl);1212	rmon->hist[9] =1213		mlxsw_reg_ppcnt_ether_stats_pkts8192to10239octets_get(ppcnt_pl);1214 1215	*ranges = mlxsw_rmon_ranges;1216}1217 1218static int mlxsw_sp_reset(struct net_device *dev, u32 *flags)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_reset_module(dev, mlxsw_sp->core, slot_index,1226				      module, flags);1227}1228 1229static int1230mlxsw_sp_get_module_power_mode(struct net_device *dev,1231			       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_get_module_power_mode(mlxsw_sp->core, slot_index,1240					       module, params, extack);1241}1242 1243static int1244mlxsw_sp_set_module_power_mode(struct net_device *dev,1245			       const struct ethtool_module_power_mode_params *params,1246			       struct netlink_ext_ack *extack)1247{1248	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);1249	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;1250	u8 slot_index = mlxsw_sp_port->mapping.slot_index;1251	u8 module = mlxsw_sp_port->mapping.module;1252 1253	return mlxsw_env_set_module_power_mode(mlxsw_sp->core, slot_index,1254					       module, params->policy, extack);1255}1256 1257const struct ethtool_ops mlxsw_sp_port_ethtool_ops = {1258	.cap_link_lanes_supported	= true,1259	.get_drvinfo			= mlxsw_sp_port_get_drvinfo,1260	.get_link			= ethtool_op_get_link,1261	.get_link_ext_state		= mlxsw_sp_port_get_link_ext_state,1262	.get_pauseparam			= mlxsw_sp_port_get_pauseparam,1263	.set_pauseparam			= mlxsw_sp_port_set_pauseparam,1264	.get_strings			= mlxsw_sp_port_get_strings,1265	.set_phys_id			= mlxsw_sp_port_set_phys_id,1266	.get_ethtool_stats		= mlxsw_sp_port_get_stats,1267	.get_sset_count			= mlxsw_sp_port_get_sset_count,1268	.get_link_ksettings		= mlxsw_sp_port_get_link_ksettings,1269	.set_link_ksettings		= mlxsw_sp_port_set_link_ksettings,1270	.get_module_info		= mlxsw_sp_get_module_info,1271	.get_module_eeprom		= mlxsw_sp_get_module_eeprom,1272	.get_module_eeprom_by_page	= mlxsw_sp_get_module_eeprom_by_page,1273	.set_module_eeprom_by_page	= mlxsw_sp_set_module_eeprom_by_page,1274	.get_ts_info			= mlxsw_sp_get_ts_info,1275	.get_eth_phy_stats		= mlxsw_sp_get_eth_phy_stats,1276	.get_eth_mac_stats		= mlxsw_sp_get_eth_mac_stats,1277	.get_eth_ctrl_stats		= mlxsw_sp_get_eth_ctrl_stats,1278	.get_rmon_stats			= mlxsw_sp_get_rmon_stats,1279	.reset				= mlxsw_sp_reset,1280	.get_module_power_mode		= mlxsw_sp_get_module_power_mode,1281	.set_module_power_mode		= mlxsw_sp_set_module_power_mode,1282};1283 1284struct mlxsw_sp1_port_link_mode {1285	enum ethtool_link_mode_bit_indices mask_ethtool;1286	u32 mask;1287	u32 speed;1288};1289 1290static const struct mlxsw_sp1_port_link_mode mlxsw_sp1_port_link_mode[] = {1291	{1292		.mask		= MLXSW_REG_PTYS_ETH_SPEED_100BASE_T,1293		.mask_ethtool	= ETHTOOL_LINK_MODE_100baseT_Full_BIT,1294		.speed		= SPEED_100,1295	},1296	{1297		.mask		= MLXSW_REG_PTYS_ETH_SPEED_SGMII |1298				  MLXSW_REG_PTYS_ETH_SPEED_1000BASE_KX,1299		.mask_ethtool	= ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,1300		.speed		= SPEED_1000,1301	},1302	{1303		.mask		= MLXSW_REG_PTYS_ETH_SPEED_1000BASE_T,1304		.mask_ethtool   = ETHTOOL_LINK_MODE_1000baseT_Full_BIT,1305		.speed          = SPEED_1000,1306	},1307	{1308		.mask		= MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CX4 |1309				  MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4,1310		.mask_ethtool	= ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,1311		.speed		= SPEED_10000,1312	},1313	{1314		.mask		= MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR |1315				  MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR |1316				  MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR |1317				  MLXSW_REG_PTYS_ETH_SPEED_10GBASE_ER_LR,1318		.mask_ethtool	= ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,1319		.speed		= SPEED_10000,1320	},1321	{1322		.mask		= MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4,1323		.mask_ethtool	= ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,1324		.speed		= SPEED_40000,1325	},1326	{1327		.mask		= MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4,1328		.mask_ethtool	= ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,1329		.speed		= SPEED_40000,1330	},1331	{1332		.mask		= MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4,1333		.mask_ethtool	= ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,1334		.speed		= SPEED_40000,1335	},1336	{1337		.mask		= MLXSW_REG_PTYS_ETH_SPEED_40GBASE_LR4_ER4,1338		.mask_ethtool	= ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,1339		.speed		= SPEED_40000,1340	},1341	{1342		.mask		= MLXSW_REG_PTYS_ETH_SPEED_25GBASE_CR,1343		.mask_ethtool	= ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,1344		.speed		= SPEED_25000,1345	},1346	{1347		.mask		= MLXSW_REG_PTYS_ETH_SPEED_25GBASE_KR,1348		.mask_ethtool	= ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,1349		.speed		= SPEED_25000,1350	},1351	{1352		.mask		= MLXSW_REG_PTYS_ETH_SPEED_25GBASE_SR,1353		.mask_ethtool	= ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,1354		.speed		= SPEED_25000,1355	},1356	{1357		.mask		= MLXSW_REG_PTYS_ETH_SPEED_50GBASE_CR2,1358		.mask_ethtool	= ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,1359		.speed		= SPEED_50000,1360	},1361	{1362		.mask		= MLXSW_REG_PTYS_ETH_SPEED_50GBASE_KR2,1363		.mask_ethtool	= ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,1364		.speed		= SPEED_50000,1365	},1366	{1367		.mask		= MLXSW_REG_PTYS_ETH_SPEED_50GBASE_SR2,1368		.mask_ethtool	= ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,1369		.speed		= SPEED_50000,1370	},1371	{1372		.mask		= MLXSW_REG_PTYS_ETH_SPEED_100GBASE_CR4,1373		.mask_ethtool	= ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,1374		.speed		= SPEED_100000,1375	},1376	{1377		.mask		= MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4,1378		.mask_ethtool	= ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,1379		.speed		= SPEED_100000,1380	},1381	{1382		.mask		= MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4,1383		.mask_ethtool	= ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,1384		.speed		= SPEED_100000,1385	},1386	{1387		.mask		= MLXSW_REG_PTYS_ETH_SPEED_100GBASE_LR4_ER4,1388		.mask_ethtool	= ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,1389		.speed		= SPEED_100000,1390	},1391};1392 1393#define MLXSW_SP1_PORT_LINK_MODE_LEN ARRAY_SIZE(mlxsw_sp1_port_link_mode)1394 1395static void1396mlxsw_sp1_from_ptys_supported_port(struct mlxsw_sp *mlxsw_sp,1397				   u32 ptys_eth_proto,1398				   struct ethtool_link_ksettings *cmd)1399{1400	if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR |1401			      MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR |1402			      MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4 |1403			      MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4 |1404			      MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4 |1405			      MLXSW_REG_PTYS_ETH_SPEED_SGMII))1406		ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);1407 1408	if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR |1409			      MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4 |1410			      MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4 |1411			      MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4 |1412			      MLXSW_REG_PTYS_ETH_SPEED_1000BASE_KX))1413		ethtool_link_ksettings_add_link_mode(cmd, supported, Backplane);1414}1415 1416static void1417mlxsw_sp1_from_ptys_link(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto,1418			 unsigned long *mode)1419{1420	int i;1421 1422	for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {1423		if (ptys_eth_proto & mlxsw_sp1_port_link_mode[i].mask)1424			__set_bit(mlxsw_sp1_port_link_mode[i].mask_ethtool,1425				  mode);1426	}1427}1428 1429static u321430mlxsw_sp1_from_ptys_speed(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto)1431{1432	int i;1433 1434	for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {1435		if (ptys_eth_proto & mlxsw_sp1_port_link_mode[i].mask)1436			return mlxsw_sp1_port_link_mode[i].speed;1437	}1438 1439	return SPEED_UNKNOWN;1440}1441 1442static void1443mlxsw_sp1_from_ptys_link_mode(struct mlxsw_sp *mlxsw_sp, bool carrier_ok,1444			      u32 ptys_eth_proto,1445			      struct ethtool_link_ksettings *cmd)1446{1447	struct mlxsw_sp1_port_link_mode link;1448	int i;1449 1450	cmd->base.speed = SPEED_UNKNOWN;1451	cmd->base.duplex = DUPLEX_UNKNOWN;1452	cmd->lanes = 0;1453 1454	if (!carrier_ok)1455		return;1456 1457	for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {1458		if (ptys_eth_proto & mlxsw_sp1_port_link_mode[i].mask) {1459			link = mlxsw_sp1_port_link_mode[i];1460			ethtool_params_from_link_mode(cmd,1461						      link.mask_ethtool);1462		}1463	}1464}1465 1466static int mlxsw_sp1_ptys_max_speed(struct mlxsw_sp_port *mlxsw_sp_port, u32 *p_max_speed)1467{1468	u32 eth_proto_cap;1469	u32 max_speed = 0;1470	int err;1471	int i;1472 1473	err = mlxsw_sp_port_ptys_query(mlxsw_sp_port, &eth_proto_cap, NULL, NULL, NULL);1474	if (err)1475		return err;1476 1477	for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {1478		if ((eth_proto_cap & mlxsw_sp1_port_link_mode[i].mask) &&1479		    mlxsw_sp1_port_link_mode[i].speed > max_speed)1480			max_speed = mlxsw_sp1_port_link_mode[i].speed;1481	}1482 1483	*p_max_speed = max_speed;1484	return 0;1485}1486 1487static u321488mlxsw_sp1_to_ptys_advert_link(struct mlxsw_sp *mlxsw_sp,1489			      const struct ethtool_link_ksettings *cmd)1490{1491	u32 ptys_proto = 0;1492	int i;1493 1494	for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {1495		if (test_bit(mlxsw_sp1_port_link_mode[i].mask_ethtool,1496			     cmd->link_modes.advertising))1497			ptys_proto |= mlxsw_sp1_port_link_mode[i].mask;1498	}1499	return ptys_proto;1500}1501 1502static u32 mlxsw_sp1_to_ptys_speed_lanes(struct mlxsw_sp *mlxsw_sp, u8 width,1503					 const struct ethtool_link_ksettings *cmd)1504{1505	u32 ptys_proto = 0;1506	int i;1507 1508	if (cmd->lanes > width)1509		return ptys_proto;1510 1511	for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {1512		if (cmd->base.speed == mlxsw_sp1_port_link_mode[i].speed)1513			ptys_proto |= mlxsw_sp1_port_link_mode[i].mask;1514	}1515	return ptys_proto;1516}1517 1518static void1519mlxsw_sp1_reg_ptys_eth_pack(struct mlxsw_sp *mlxsw_sp, char *payload,1520			    u16 local_port, u32 proto_admin, bool autoneg)1521{1522	mlxsw_reg_ptys_eth_pack(payload, local_port, proto_admin, autoneg);1523}1524 1525static void1526mlxsw_sp1_reg_ptys_eth_unpack(struct mlxsw_sp *mlxsw_sp, char *payload,1527			      u32 *p_eth_proto_cap, u32 *p_eth_proto_admin,1528			      u32 *p_eth_proto_oper)1529{1530	mlxsw_reg_ptys_eth_unpack(payload, p_eth_proto_cap, p_eth_proto_admin,1531				  p_eth_proto_oper);1532}1533 1534static u32 mlxsw_sp1_ptys_proto_cap_masked_get(u32 eth_proto_cap)1535{1536	u32 ptys_proto_cap_masked = 0;1537	int i;1538 1539	for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {1540		if (mlxsw_sp1_port_link_mode[i].mask & eth_proto_cap)1541			ptys_proto_cap_masked |=1542				mlxsw_sp1_port_link_mode[i].mask;1543	}1544 1545	return ptys_proto_cap_masked;1546}1547 1548const struct mlxsw_sp_port_type_speed_ops mlxsw_sp1_port_type_speed_ops = {1549	.from_ptys_supported_port	= mlxsw_sp1_from_ptys_supported_port,1550	.from_ptys_link			= mlxsw_sp1_from_ptys_link,1551	.from_ptys_speed		= mlxsw_sp1_from_ptys_speed,1552	.from_ptys_link_mode		= mlxsw_sp1_from_ptys_link_mode,1553	.ptys_max_speed			= mlxsw_sp1_ptys_max_speed,1554	.to_ptys_advert_link		= mlxsw_sp1_to_ptys_advert_link,1555	.to_ptys_speed_lanes		= mlxsw_sp1_to_ptys_speed_lanes,1556	.reg_ptys_eth_pack		= mlxsw_sp1_reg_ptys_eth_pack,1557	.reg_ptys_eth_unpack		= mlxsw_sp1_reg_ptys_eth_unpack,1558	.ptys_proto_cap_masked_get	= mlxsw_sp1_ptys_proto_cap_masked_get,1559};1560 1561static const enum ethtool_link_mode_bit_indices1562mlxsw_sp2_mask_ethtool_sgmii_100m[] = {1563	ETHTOOL_LINK_MODE_100baseT_Full_BIT,1564};1565 1566#define MLXSW_SP2_MASK_ETHTOOL_SGMII_100M_LEN \1567	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_sgmii_100m)1568 1569static const enum ethtool_link_mode_bit_indices1570mlxsw_sp2_mask_ethtool_1000base_x_sgmii[] = {1571	ETHTOOL_LINK_MODE_1000baseT_Full_BIT,1572	ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,1573};1574 1575#define MLXSW_SP2_MASK_ETHTOOL_1000BASE_X_SGMII_LEN \1576	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_1000base_x_sgmii)1577 1578static const enum ethtool_link_mode_bit_indices1579mlxsw_sp2_mask_ethtool_5gbase_r[] = {1580	ETHTOOL_LINK_MODE_5000baseT_Full_BIT,1581};1582 1583#define MLXSW_SP2_MASK_ETHTOOL_5GBASE_R_LEN \1584	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_5gbase_r)1585 1586static const enum ethtool_link_mode_bit_indices1587mlxsw_sp2_mask_ethtool_xfi_xaui_1_10g[] = {1588	ETHTOOL_LINK_MODE_10000baseT_Full_BIT,1589	ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,1590	ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,1591	ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,1592	ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,1593	ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,1594	ETHTOOL_LINK_MODE_10000baseER_Full_BIT,1595};1596 1597#define MLXSW_SP2_MASK_ETHTOOL_XFI_XAUI_1_10G_LEN \1598	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_xfi_xaui_1_10g)1599 1600static const enum ethtool_link_mode_bit_indices1601mlxsw_sp2_mask_ethtool_xlaui_4_xlppi_4_40g[] = {1602	ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,1603	ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,1604	ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,1605	ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,1606};1607 1608#define MLXSW_SP2_MASK_ETHTOOL_XLAUI_4_XLPPI_4_40G_LEN \1609	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_xlaui_4_xlppi_4_40g)1610 1611static const enum ethtool_link_mode_bit_indices1612mlxsw_sp2_mask_ethtool_25gaui_1_25gbase_cr_kr[] = {1613	ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,1614	ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,1615	ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,1616};1617 1618#define MLXSW_SP2_MASK_ETHTOOL_25GAUI_1_25GBASE_CR_KR_LEN \1619	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_25gaui_1_25gbase_cr_kr)1620 1621static const enum ethtool_link_mode_bit_indices1622mlxsw_sp2_mask_ethtool_50gaui_2_laui_2_50gbase_cr2_kr2[] = {1623	ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,1624	ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,1625	ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,1626};1627 1628#define MLXSW_SP2_MASK_ETHTOOL_50GAUI_2_LAUI_2_50GBASE_CR2_KR2_LEN \1629	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_50gaui_2_laui_2_50gbase_cr2_kr2)1630 1631static const enum ethtool_link_mode_bit_indices1632mlxsw_sp2_mask_ethtool_50gaui_1_laui_1_50gbase_cr_kr[] = {1633	ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,1634	ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,1635	ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,1636	ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,1637	ETHTOOL_LINK_MODE_50000baseDR_Full_BIT,1638};1639 1640#define MLXSW_SP2_MASK_ETHTOOL_50GAUI_1_LAUI_1_50GBASE_CR_KR_LEN \1641	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_50gaui_1_laui_1_50gbase_cr_kr)1642 1643static const enum ethtool_link_mode_bit_indices1644mlxsw_sp2_mask_ethtool_caui_4_100gbase_cr4_kr4[] = {1645	ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,1646	ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,1647	ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,1648	ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,1649};1650 1651#define MLXSW_SP2_MASK_ETHTOOL_CAUI_4_100GBASE_CR4_KR4_LEN \1652	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_caui_4_100gbase_cr4_kr4)1653 1654static const enum ethtool_link_mode_bit_indices1655mlxsw_sp2_mask_ethtool_100gaui_2_100gbase_cr2_kr2[] = {1656	ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT,1657	ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT,1658	ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT,1659	ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,1660	ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT,1661};1662 1663#define MLXSW_SP2_MASK_ETHTOOL_100GAUI_2_100GBASE_CR2_KR2_LEN \1664	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_100gaui_2_100gbase_cr2_kr2)1665 1666static const enum ethtool_link_mode_bit_indices1667mlxsw_sp2_mask_ethtool_100gaui_1_100gbase_cr_kr[] = {1668	ETHTOOL_LINK_MODE_100000baseKR_Full_BIT,1669	ETHTOOL_LINK_MODE_100000baseSR_Full_BIT,1670	ETHTOOL_LINK_MODE_100000baseLR_ER_FR_Full_BIT,1671	ETHTOOL_LINK_MODE_100000baseCR_Full_BIT,1672	ETHTOOL_LINK_MODE_100000baseDR_Full_BIT,1673};1674 1675#define MLXSW_SP2_MASK_ETHTOOL_100GAUI_1_100GBASE_CR_KR_LEN \1676	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_100gaui_1_100gbase_cr_kr)1677 1678static const enum ethtool_link_mode_bit_indices1679mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4[] = {1680	ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT,1681	ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT,1682	ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT,1683	ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT,1684	ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT,1685};1686 1687#define MLXSW_SP2_MASK_ETHTOOL_200GAUI_4_200GBASE_CR4_KR4_LEN \1688	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4)1689 1690static const enum ethtool_link_mode_bit_indices1691mlxsw_sp2_mask_ethtool_200gaui_2_200gbase_cr2_kr2[] = {1692	ETHTOOL_LINK_MODE_200000baseKR2_Full_BIT,1693	ETHTOOL_LINK_MODE_200000baseSR2_Full_BIT,1694	ETHTOOL_LINK_MODE_200000baseLR2_ER2_FR2_Full_BIT,1695	ETHTOOL_LINK_MODE_200000baseDR2_Full_BIT,1696	ETHTOOL_LINK_MODE_200000baseCR2_Full_BIT,1697};1698 1699#define MLXSW_SP2_MASK_ETHTOOL_200GAUI_2_200GBASE_CR2_KR2_LEN \1700	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_200gaui_2_200gbase_cr2_kr2)1701 1702static const enum ethtool_link_mode_bit_indices1703mlxsw_sp2_mask_ethtool_400gaui_8[] = {1704	ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT,1705	ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT,1706	ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT,1707	ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT,1708	ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT,1709};1710 1711#define MLXSW_SP2_MASK_ETHTOOL_400GAUI_8_LEN \1712	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_400gaui_8)1713 1714static const enum ethtool_link_mode_bit_indices1715mlxsw_sp2_mask_ethtool_400gaui_4_400gbase_cr4_kr4[] = {1716	ETHTOOL_LINK_MODE_400000baseKR4_Full_BIT,1717	ETHTOOL_LINK_MODE_400000baseSR4_Full_BIT,1718	ETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT,1719	ETHTOOL_LINK_MODE_400000baseDR4_Full_BIT,1720	ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT,1721};1722 1723#define MLXSW_SP2_MASK_ETHTOOL_400GAUI_4_400GBASE_CR4_KR4_LEN \1724	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_400gaui_4_400gbase_cr4_kr4)1725 1726static const enum ethtool_link_mode_bit_indices1727mlxsw_sp2_mask_ethtool_800gaui_8[] = {1728	ETHTOOL_LINK_MODE_800000baseCR8_Full_BIT,1729	ETHTOOL_LINK_MODE_800000baseKR8_Full_BIT,1730	ETHTOOL_LINK_MODE_800000baseDR8_Full_BIT,1731	ETHTOOL_LINK_MODE_800000baseDR8_2_Full_BIT,1732	ETHTOOL_LINK_MODE_800000baseSR8_Full_BIT,1733	ETHTOOL_LINK_MODE_800000baseVR8_Full_BIT,1734};1735 1736#define MLXSW_SP2_MASK_ETHTOOL_800GAUI_8_LEN \1737	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_800gaui_8)1738 1739#define MLXSW_SP_PORT_MASK_WIDTH_1X	BIT(0)1740#define MLXSW_SP_PORT_MASK_WIDTH_2X	BIT(1)1741#define MLXSW_SP_PORT_MASK_WIDTH_4X	BIT(2)1742#define MLXSW_SP_PORT_MASK_WIDTH_8X	BIT(3)1743 1744static u8 mlxsw_sp_port_mask_width_get(u8 width)1745{1746	switch (width) {1747	case 1:1748		return MLXSW_SP_PORT_MASK_WIDTH_1X;1749	case 2:1750		return MLXSW_SP_PORT_MASK_WIDTH_2X;1751	case 4:1752		return MLXSW_SP_PORT_MASK_WIDTH_4X;1753	case 8:1754		return MLXSW_SP_PORT_MASK_WIDTH_8X;1755	default:1756		WARN_ON_ONCE(1);1757		return 0;1758	}1759}1760 1761struct mlxsw_sp2_port_link_mode {1762	const enum ethtool_link_mode_bit_indices *mask_ethtool;1763	int m_ethtool_len;1764	u32 mask;1765	u32 speed;1766	u32 width;1767	u8 mask_sup_width;1768};1769 1770static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = {1771	{1772		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_SGMII_100M,1773		.mask_ethtool	= mlxsw_sp2_mask_ethtool_sgmii_100m,1774		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_SGMII_100M_LEN,1775		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_1X |1776				  MLXSW_SP_PORT_MASK_WIDTH_2X |1777				  MLXSW_SP_PORT_MASK_WIDTH_4X |1778				  MLXSW_SP_PORT_MASK_WIDTH_8X,1779		.speed		= SPEED_100,1780		.width		= 1,1781	},1782	{1783		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_1000BASE_X_SGMII,1784		.mask_ethtool	= mlxsw_sp2_mask_ethtool_1000base_x_sgmii,1785		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_1000BASE_X_SGMII_LEN,1786		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_1X |1787				  MLXSW_SP_PORT_MASK_WIDTH_2X |1788				  MLXSW_SP_PORT_MASK_WIDTH_4X |1789				  MLXSW_SP_PORT_MASK_WIDTH_8X,1790		.speed		= SPEED_1000,1791		.width		= 1,1792	},1793	{1794		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_5GBASE_R,1795		.mask_ethtool	= mlxsw_sp2_mask_ethtool_5gbase_r,1796		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_5GBASE_R_LEN,1797		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_1X |1798				  MLXSW_SP_PORT_MASK_WIDTH_2X |1799				  MLXSW_SP_PORT_MASK_WIDTH_4X |1800				  MLXSW_SP_PORT_MASK_WIDTH_8X,1801		.speed		= SPEED_5000,1802		.width		= 1,1803	},1804	{1805		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_XFI_XAUI_1_10G,1806		.mask_ethtool	= mlxsw_sp2_mask_ethtool_xfi_xaui_1_10g,1807		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_XFI_XAUI_1_10G_LEN,1808		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_1X |1809				  MLXSW_SP_PORT_MASK_WIDTH_2X |1810				  MLXSW_SP_PORT_MASK_WIDTH_4X |1811				  MLXSW_SP_PORT_MASK_WIDTH_8X,1812		.speed		= SPEED_10000,1813		.width		= 1,1814	},1815	{1816		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_XLAUI_4_XLPPI_4_40G,1817		.mask_ethtool	= mlxsw_sp2_mask_ethtool_xlaui_4_xlppi_4_40g,1818		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_XLAUI_4_XLPPI_4_40G_LEN,1819		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_4X |1820				  MLXSW_SP_PORT_MASK_WIDTH_8X,1821		.speed		= SPEED_40000,1822		.width		= 4,1823	},1824	{1825		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_25GAUI_1_25GBASE_CR_KR,1826		.mask_ethtool	= mlxsw_sp2_mask_ethtool_25gaui_1_25gbase_cr_kr,1827		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_25GAUI_1_25GBASE_CR_KR_LEN,1828		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_1X |1829				  MLXSW_SP_PORT_MASK_WIDTH_2X |1830				  MLXSW_SP_PORT_MASK_WIDTH_4X |1831				  MLXSW_SP_PORT_MASK_WIDTH_8X,1832		.speed		= SPEED_25000,1833		.width		= 1,1834	},1835	{1836		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_50GAUI_2_LAUI_2_50GBASE_CR2_KR2,1837		.mask_ethtool	= mlxsw_sp2_mask_ethtool_50gaui_2_laui_2_50gbase_cr2_kr2,1838		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_50GAUI_2_LAUI_2_50GBASE_CR2_KR2_LEN,1839		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_2X |1840				  MLXSW_SP_PORT_MASK_WIDTH_4X |1841				  MLXSW_SP_PORT_MASK_WIDTH_8X,1842		.speed		= SPEED_50000,1843		.width		= 2,1844	},1845	{1846		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_50GAUI_1_LAUI_1_50GBASE_CR_KR,1847		.mask_ethtool	= mlxsw_sp2_mask_ethtool_50gaui_1_laui_1_50gbase_cr_kr,1848		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_50GAUI_1_LAUI_1_50GBASE_CR_KR_LEN,1849		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_1X,1850		.speed		= SPEED_50000,1851		.width		= 1,1852	},1853	{1854		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_CAUI_4_100GBASE_CR4_KR4,1855		.mask_ethtool	= mlxsw_sp2_mask_ethtool_caui_4_100gbase_cr4_kr4,1856		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_CAUI_4_100GBASE_CR4_KR4_LEN,1857		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_4X |1858				  MLXSW_SP_PORT_MASK_WIDTH_8X,1859		.speed		= SPEED_100000,1860		.width		= 4,1861	},1862	{1863		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_100GAUI_2_100GBASE_CR2_KR2,1864		.mask_ethtool	= mlxsw_sp2_mask_ethtool_100gaui_2_100gbase_cr2_kr2,1865		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_100GAUI_2_100GBASE_CR2_KR2_LEN,1866		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_2X,1867		.speed		= SPEED_100000,1868		.width		= 2,1869	},1870	{1871		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_100GAUI_1_100GBASE_CR_KR,1872		.mask_ethtool	= mlxsw_sp2_mask_ethtool_100gaui_1_100gbase_cr_kr,1873		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_100GAUI_1_100GBASE_CR_KR_LEN,1874		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_1X,1875		.speed		= SPEED_100000,1876		.width		= 1,1877	},1878	{1879		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_200GAUI_4_200GBASE_CR4_KR4,1880		.mask_ethtool	= mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4,1881		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_200GAUI_4_200GBASE_CR4_KR4_LEN,1882		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_4X |1883				  MLXSW_SP_PORT_MASK_WIDTH_8X,1884		.speed		= SPEED_200000,1885		.width		= 4,1886	},1887	{1888		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_200GAUI_2_200GBASE_CR2_KR2,1889		.mask_ethtool	= mlxsw_sp2_mask_ethtool_200gaui_2_200gbase_cr2_kr2,1890		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_200GAUI_2_200GBASE_CR2_KR2_LEN,1891		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_2X,1892		.speed		= SPEED_200000,1893		.width		= 2,1894	},1895	{1896		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_400GAUI_8,1897		.mask_ethtool	= mlxsw_sp2_mask_ethtool_400gaui_8,1898		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_400GAUI_8_LEN,1899		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_8X,1900		.speed		= SPEED_400000,1901		.width		= 8,1902	},1903	{1904		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_400GAUI_4_400GBASE_CR4_KR4,1905		.mask_ethtool	= mlxsw_sp2_mask_ethtool_400gaui_4_400gbase_cr4_kr4,1906		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_400GAUI_4_400GBASE_CR4_KR4_LEN,1907		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_4X,1908		.speed		= SPEED_400000,1909		.width		= 4,1910	},1911	{1912		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_800GAUI_8,1913		.mask_ethtool	= mlxsw_sp2_mask_ethtool_800gaui_8,1914		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_800GAUI_8_LEN,1915		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_8X,1916		.speed		= SPEED_800000,1917		.width		= 8,1918	},1919};1920 1921#define MLXSW_SP2_PORT_LINK_MODE_LEN ARRAY_SIZE(mlxsw_sp2_port_link_mode)1922 1923static void1924mlxsw_sp2_from_ptys_supported_port(struct mlxsw_sp *mlxsw_sp,1925				   u32 ptys_eth_proto,1926				   struct ethtool_link_ksettings *cmd)1927{1928	ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);1929	ethtool_link_ksettings_add_link_mode(cmd, supported, Backplane);1930}1931 1932static void1933mlxsw_sp2_set_bit_ethtool(const struct mlxsw_sp2_port_link_mode *link_mode,1934			  unsigned long *mode)1935{1936	int i;1937 1938	for (i = 0; i < link_mode->m_ethtool_len; i++)1939		__set_bit(link_mode->mask_ethtool[i], mode);1940}1941 1942static void1943mlxsw_sp2_from_ptys_link(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto,1944			 unsigned long *mode)1945{1946	int i;1947 1948	for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {1949		if (ptys_eth_proto & mlxsw_sp2_port_link_mode[i].mask)1950			mlxsw_sp2_set_bit_ethtool(&mlxsw_sp2_port_link_mode[i],1951						  mode);1952	}1953}1954 1955static u321956mlxsw_sp2_from_ptys_speed(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto)1957{1958	int i;1959 1960	for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {1961		if (ptys_eth_proto & mlxsw_sp2_port_link_mode[i].mask)1962			return mlxsw_sp2_port_link_mode[i].speed;1963	}1964 1965	return SPEED_UNKNOWN;1966}1967 1968static void1969mlxsw_sp2_from_ptys_link_mode(struct mlxsw_sp *mlxsw_sp, bool carrier_ok,1970			      u32 ptys_eth_proto,1971			      struct ethtool_link_ksettings *cmd)1972{1973	struct mlxsw_sp2_port_link_mode link;1974	int i;1975 1976	cmd->base.speed = SPEED_UNKNOWN;1977	cmd->base.duplex = DUPLEX_UNKNOWN;1978	cmd->lanes = 0;1979 1980	if (!carrier_ok)1981		return;1982 1983	for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {1984		if (ptys_eth_proto & mlxsw_sp2_port_link_mode[i].mask) {1985			link = mlxsw_sp2_port_link_mode[i];1986			ethtool_params_from_link_mode(cmd,1987						      link.mask_ethtool[1]);1988		}1989	}1990}1991 1992static int mlxsw_sp2_ptys_max_speed(struct mlxsw_sp_port *mlxsw_sp_port, u32 *p_max_speed)1993{1994	u32 eth_proto_cap;1995	u32 max_speed = 0;1996	int err;1997	int i;1998 1999	err = mlxsw_sp_port_ptys_query(mlxsw_sp_port, &eth_proto_cap, NULL, NULL, NULL);2000	if (err)2001		return err;2002 2003	for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {2004		if ((eth_proto_cap & mlxsw_sp2_port_link_mode[i].mask) &&2005		    mlxsw_sp2_port_link_mode[i].speed > max_speed)2006			max_speed = mlxsw_sp2_port_link_mode[i].speed;2007	}2008 2009	*p_max_speed = max_speed;2010	return 0;2011}2012 2013static bool2014mlxsw_sp2_test_bit_ethtool(const struct mlxsw_sp2_port_link_mode *link_mode,2015			   const unsigned long *mode)2016{2017	int cnt = 0;2018	int i;2019 2020	for (i = 0; i < link_mode->m_ethtool_len; i++) {2021		if (test_bit(link_mode->mask_ethtool[i], mode))2022			cnt++;2023	}2024 2025	return cnt == link_mode->m_ethtool_len;2026}2027 2028static u322029mlxsw_sp2_to_ptys_advert_link(struct mlxsw_sp *mlxsw_sp,2030			      const struct ethtool_link_ksettings *cmd)2031{2032	u32 ptys_proto = 0;2033	int i;2034 2035	for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {2036		if (mlxsw_sp2_test_bit_ethtool(&mlxsw_sp2_port_link_mode[i],2037					       cmd->link_modes.advertising))2038			ptys_proto |= mlxsw_sp2_port_link_mode[i].mask;2039	}2040	return ptys_proto;2041}2042 2043static u32 mlxsw_sp2_to_ptys_speed_lanes(struct mlxsw_sp *mlxsw_sp, u8 width,2044					 const struct ethtool_link_ksettings *cmd)2045{2046	u8 mask_width = mlxsw_sp_port_mask_width_get(width);2047	struct mlxsw_sp2_port_link_mode link_mode;2048	u32 ptys_proto = 0;2049	int i;2050 2051	if (cmd->lanes > width)2052		return ptys_proto;2053 2054	for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {2055		if (cmd->base.speed == mlxsw_sp2_port_link_mode[i].speed) {2056			link_mode = mlxsw_sp2_port_link_mode[i];2057 2058			if (!cmd->lanes) {2059				/* If number of lanes was not set by user space,2060				 * choose the link mode that supports the width2061				 * of the port.2062				 */2063				if (mask_width & link_mode.mask_sup_width)2064					ptys_proto |= link_mode.mask;2065			} else if (cmd->lanes == link_mode.width) {2066				/* Else if the number of lanes was set, choose2067				 * the link mode that its actual width equals to2068				 * it.2069				 */2070				ptys_proto |= link_mode.mask;2071			}2072		}2073	}2074	return ptys_proto;2075}2076 2077static void2078mlxsw_sp2_reg_ptys_eth_pack(struct mlxsw_sp *mlxsw_sp, char *payload,2079			    u16 local_port, u32 proto_admin,2080			    bool autoneg)2081{2082	mlxsw_reg_ptys_ext_eth_pack(payload, local_port, proto_admin, autoneg);2083}2084 2085static void2086mlxsw_sp2_reg_ptys_eth_unpack(struct mlxsw_sp *mlxsw_sp, char *payload,2087			      u32 *p_eth_proto_cap, u32 *p_eth_proto_admin,2088			      u32 *p_eth_proto_oper)2089{2090	mlxsw_reg_ptys_ext_eth_unpack(payload, p_eth_proto_cap,2091				      p_eth_proto_admin, p_eth_proto_oper);2092}2093 2094static u32 mlxsw_sp2_ptys_proto_cap_masked_get(u32 eth_proto_cap)2095{2096	u32 ptys_proto_cap_masked = 0;2097	int i;2098 2099	for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {2100		if (mlxsw_sp2_port_link_mode[i].mask & eth_proto_cap)2101			ptys_proto_cap_masked |=2102				mlxsw_sp2_port_link_mode[i].mask;2103	}2104 2105	return ptys_proto_cap_masked;2106}2107 2108const struct mlxsw_sp_port_type_speed_ops mlxsw_sp2_port_type_speed_ops = {2109	.from_ptys_supported_port	= mlxsw_sp2_from_ptys_supported_port,2110	.from_ptys_link			= mlxsw_sp2_from_ptys_link,2111	.from_ptys_speed		= mlxsw_sp2_from_ptys_speed,2112	.from_ptys_link_mode		= mlxsw_sp2_from_ptys_link_mode,2113	.ptys_max_speed			= mlxsw_sp2_ptys_max_speed,2114	.to_ptys_advert_link		= mlxsw_sp2_to_ptys_advert_link,2115	.to_ptys_speed_lanes		= mlxsw_sp2_to_ptys_speed_lanes,2116	.reg_ptys_eth_pack		= mlxsw_sp2_reg_ptys_eth_pack,2117	.reg_ptys_eth_unpack		= mlxsw_sp2_reg_ptys_eth_unpack,2118	.ptys_proto_cap_masked_get	= mlxsw_sp2_ptys_proto_cap_masked_get,2119};2120