xref: /openbmc/linux/drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
1614d509aSAmit Cohen // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2614d509aSAmit Cohen /* Copyright (c) 2020 Mellanox Technologies. All rights reserved */
3614d509aSAmit Cohen 
4614d509aSAmit Cohen #include "reg.h"
569f6d4eeSAmit Cohen #include "core.h"
6614d509aSAmit Cohen #include "spectrum.h"
7614d509aSAmit Cohen #include "core_env.h"
8614d509aSAmit Cohen 
9614d509aSAmit Cohen static const char mlxsw_sp_driver_version[] = "1.0";
10614d509aSAmit Cohen 
mlxsw_sp_port_get_drvinfo(struct net_device * dev,struct ethtool_drvinfo * drvinfo)11614d509aSAmit Cohen static void mlxsw_sp_port_get_drvinfo(struct net_device *dev,
12614d509aSAmit Cohen 				      struct ethtool_drvinfo *drvinfo)
13614d509aSAmit Cohen {
14614d509aSAmit Cohen 	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
15614d509aSAmit Cohen 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
16614d509aSAmit Cohen 
17f029c781SWolfram Sang 	strscpy(drvinfo->driver, mlxsw_sp->bus_info->device_kind,
18614d509aSAmit Cohen 		sizeof(drvinfo->driver));
19f029c781SWolfram Sang 	strscpy(drvinfo->version, mlxsw_sp_driver_version,
20614d509aSAmit Cohen 		sizeof(drvinfo->version));
21614d509aSAmit Cohen 	snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
22614d509aSAmit Cohen 		 "%d.%d.%d",
23614d509aSAmit Cohen 		 mlxsw_sp->bus_info->fw_rev.major,
24614d509aSAmit Cohen 		 mlxsw_sp->bus_info->fw_rev.minor,
25614d509aSAmit Cohen 		 mlxsw_sp->bus_info->fw_rev.subminor);
26f029c781SWolfram Sang 	strscpy(drvinfo->bus_info, mlxsw_sp->bus_info->device_name,
27614d509aSAmit Cohen 		sizeof(drvinfo->bus_info));
28614d509aSAmit Cohen }
29614d509aSAmit Cohen 
3060f30cd6SAmit Cohen struct mlxsw_sp_ethtool_link_ext_state_opcode_mapping {
3160f30cd6SAmit Cohen 	u32 status_opcode;
3260f30cd6SAmit Cohen 	enum ethtool_link_ext_state link_ext_state;
3360f30cd6SAmit Cohen 	u8 link_ext_substate;
3460f30cd6SAmit Cohen };
3560f30cd6SAmit Cohen 
3660f30cd6SAmit Cohen static const struct mlxsw_sp_ethtool_link_ext_state_opcode_mapping
3760f30cd6SAmit Cohen mlxsw_sp_link_ext_state_opcode_map[] = {
3860f30cd6SAmit Cohen 	{2, ETHTOOL_LINK_EXT_STATE_AUTONEG,
3960f30cd6SAmit Cohen 		ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED},
4060f30cd6SAmit Cohen 	{3, ETHTOOL_LINK_EXT_STATE_AUTONEG,
4160f30cd6SAmit Cohen 		ETHTOOL_LINK_EXT_SUBSTATE_AN_ACK_NOT_RECEIVED},
4260f30cd6SAmit Cohen 	{4, ETHTOOL_LINK_EXT_STATE_AUTONEG,
4360f30cd6SAmit Cohen 		ETHTOOL_LINK_EXT_SUBSTATE_AN_NEXT_PAGE_EXCHANGE_FAILED},
4460f30cd6SAmit Cohen 	{36, ETHTOOL_LINK_EXT_STATE_AUTONEG,
4560f30cd6SAmit Cohen 		ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED_FORCE_MODE},
4660f30cd6SAmit Cohen 	{38, ETHTOOL_LINK_EXT_STATE_AUTONEG,
4760f30cd6SAmit Cohen 		ETHTOOL_LINK_EXT_SUBSTATE_AN_FEC_MISMATCH_DURING_OVERRIDE},
4860f30cd6SAmit Cohen 	{39, ETHTOOL_LINK_EXT_STATE_AUTONEG,
4960f30cd6SAmit Cohen 		ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_HCD},
5060f30cd6SAmit Cohen 
5160f30cd6SAmit Cohen 	{5, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE,
5260f30cd6SAmit Cohen 		ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_FRAME_LOCK_NOT_ACQUIRED},
5360f30cd6SAmit Cohen 	{6, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE,
5460f30cd6SAmit Cohen 		ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_INHIBIT_TIMEOUT},
5560f30cd6SAmit Cohen 	{7, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE,
5660f30cd6SAmit Cohen 		ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_PARTNER_DID_NOT_SET_RECEIVER_READY},
5760f30cd6SAmit Cohen 	{8, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE, 0},
5860f30cd6SAmit Cohen 	{14, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE,
5960f30cd6SAmit Cohen 		ETHTOOL_LINK_EXT_SUBSTATE_LT_REMOTE_FAULT},
6060f30cd6SAmit Cohen 
6160f30cd6SAmit Cohen 	{9, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
6260f30cd6SAmit Cohen 		ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_BLOCK_LOCK},
6360f30cd6SAmit Cohen 	{10, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
6460f30cd6SAmit Cohen 		ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_AM_LOCK},
6560f30cd6SAmit Cohen 	{11, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
6660f30cd6SAmit Cohen 		ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_GET_ALIGN_STATUS},
6760f30cd6SAmit Cohen 	{12, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
6860f30cd6SAmit Cohen 		ETHTOOL_LINK_EXT_SUBSTATE_LLM_FC_FEC_IS_NOT_LOCKED},
6960f30cd6SAmit Cohen 	{13, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
7060f30cd6SAmit Cohen 		ETHTOOL_LINK_EXT_SUBSTATE_LLM_RS_FEC_IS_NOT_LOCKED},
7160f30cd6SAmit Cohen 
7260f30cd6SAmit Cohen 	{15, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY, 0},
7360f30cd6SAmit Cohen 	{17, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY,
7460f30cd6SAmit Cohen 		ETHTOOL_LINK_EXT_SUBSTATE_BSI_LARGE_NUMBER_OF_PHYSICAL_ERRORS},
7560f30cd6SAmit Cohen 	{42, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY,
7660f30cd6SAmit Cohen 		ETHTOOL_LINK_EXT_SUBSTATE_BSI_UNSUPPORTED_RATE},
7760f30cd6SAmit Cohen 
7860f30cd6SAmit Cohen 	{1024, ETHTOOL_LINK_EXT_STATE_NO_CABLE, 0},
7960f30cd6SAmit Cohen 
8060f30cd6SAmit Cohen 	{16, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE,
8160f30cd6SAmit Cohen 		ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE},
8260f30cd6SAmit Cohen 	{20, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE,
8360f30cd6SAmit Cohen 		ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE},
8460f30cd6SAmit Cohen 	{29, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE,
8560f30cd6SAmit Cohen 		ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE},
8660f30cd6SAmit Cohen 	{1025, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE,
8760f30cd6SAmit Cohen 		ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE},
8860f30cd6SAmit Cohen 	{1029, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE,
8960f30cd6SAmit Cohen 		ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE},
9060f30cd6SAmit Cohen 	{1031, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE, 0},
9160f30cd6SAmit Cohen 
9260f30cd6SAmit Cohen 	{1027, ETHTOOL_LINK_EXT_STATE_EEPROM_ISSUE, 0},
9360f30cd6SAmit Cohen 
9460f30cd6SAmit Cohen 	{23, ETHTOOL_LINK_EXT_STATE_CALIBRATION_FAILURE, 0},
9560f30cd6SAmit Cohen 
9660f30cd6SAmit Cohen 	{1032, ETHTOOL_LINK_EXT_STATE_POWER_BUDGET_EXCEEDED, 0},
9760f30cd6SAmit Cohen 
9860f30cd6SAmit Cohen 	{1030, ETHTOOL_LINK_EXT_STATE_OVERHEAT, 0},
99235dbbecSIdo Schimmel 
100235dbbecSIdo Schimmel 	{1042, ETHTOOL_LINK_EXT_STATE_MODULE,
101235dbbecSIdo Schimmel 	 ETHTOOL_LINK_EXT_SUBSTATE_MODULE_CMIS_NOT_READY},
10260f30cd6SAmit Cohen };
10360f30cd6SAmit Cohen 
10460f30cd6SAmit Cohen static void
mlxsw_sp_port_set_link_ext_state(struct mlxsw_sp_ethtool_link_ext_state_opcode_mapping link_ext_state_mapping,struct ethtool_link_ext_state_info * link_ext_state_info)10560f30cd6SAmit Cohen mlxsw_sp_port_set_link_ext_state(struct mlxsw_sp_ethtool_link_ext_state_opcode_mapping
10660f30cd6SAmit Cohen 				 link_ext_state_mapping,
10760f30cd6SAmit Cohen 				 struct ethtool_link_ext_state_info *link_ext_state_info)
10860f30cd6SAmit Cohen {
10960f30cd6SAmit Cohen 	switch (link_ext_state_mapping.link_ext_state) {
11060f30cd6SAmit Cohen 	case ETHTOOL_LINK_EXT_STATE_AUTONEG:
11160f30cd6SAmit Cohen 		link_ext_state_info->autoneg =
11260f30cd6SAmit Cohen 			link_ext_state_mapping.link_ext_substate;
11360f30cd6SAmit Cohen 		break;
11460f30cd6SAmit Cohen 	case ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE:
11560f30cd6SAmit Cohen 		link_ext_state_info->link_training =
11660f30cd6SAmit Cohen 			link_ext_state_mapping.link_ext_substate;
11760f30cd6SAmit Cohen 		break;
11860f30cd6SAmit Cohen 	case ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH:
11960f30cd6SAmit Cohen 		link_ext_state_info->link_logical_mismatch =
12060f30cd6SAmit Cohen 			link_ext_state_mapping.link_ext_substate;
12160f30cd6SAmit Cohen 		break;
12260f30cd6SAmit Cohen 	case ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY:
12360f30cd6SAmit Cohen 		link_ext_state_info->bad_signal_integrity =
12460f30cd6SAmit Cohen 			link_ext_state_mapping.link_ext_substate;
12560f30cd6SAmit Cohen 		break;
12660f30cd6SAmit Cohen 	case ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE:
12760f30cd6SAmit Cohen 		link_ext_state_info->cable_issue =
12860f30cd6SAmit Cohen 			link_ext_state_mapping.link_ext_substate;
12960f30cd6SAmit Cohen 		break;
130235dbbecSIdo Schimmel 	case ETHTOOL_LINK_EXT_STATE_MODULE:
131235dbbecSIdo Schimmel 		link_ext_state_info->module =
132235dbbecSIdo Schimmel 			link_ext_state_mapping.link_ext_substate;
133235dbbecSIdo Schimmel 		break;
13460f30cd6SAmit Cohen 	default:
13560f30cd6SAmit Cohen 		break;
13660f30cd6SAmit Cohen 	}
13760f30cd6SAmit Cohen 
13860f30cd6SAmit Cohen 	link_ext_state_info->link_ext_state = link_ext_state_mapping.link_ext_state;
13960f30cd6SAmit Cohen }
14060f30cd6SAmit Cohen 
14160f30cd6SAmit Cohen static int
mlxsw_sp_port_get_link_ext_state(struct net_device * dev,struct ethtool_link_ext_state_info * link_ext_state_info)14260f30cd6SAmit Cohen mlxsw_sp_port_get_link_ext_state(struct net_device *dev,
14360f30cd6SAmit Cohen 				 struct ethtool_link_ext_state_info *link_ext_state_info)
14460f30cd6SAmit Cohen {
14560f30cd6SAmit Cohen 	struct mlxsw_sp_ethtool_link_ext_state_opcode_mapping link_ext_state_mapping;
14660f30cd6SAmit Cohen 	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
14760f30cd6SAmit Cohen 	char pddr_pl[MLXSW_REG_PDDR_LEN];
14860f30cd6SAmit Cohen 	int opcode, err, i;
14960f30cd6SAmit Cohen 	u32 status_opcode;
15060f30cd6SAmit Cohen 
15160f30cd6SAmit Cohen 	if (netif_carrier_ok(dev))
15260f30cd6SAmit Cohen 		return -ENODATA;
15360f30cd6SAmit Cohen 
15460f30cd6SAmit Cohen 	mlxsw_reg_pddr_pack(pddr_pl, mlxsw_sp_port->local_port,
15560f30cd6SAmit Cohen 			    MLXSW_REG_PDDR_PAGE_SELECT_TROUBLESHOOTING_INFO);
15660f30cd6SAmit Cohen 
15760f30cd6SAmit Cohen 	opcode = MLXSW_REG_PDDR_TRBLSH_GROUP_OPCODE_MONITOR;
15860f30cd6SAmit Cohen 	mlxsw_reg_pddr_trblsh_group_opcode_set(pddr_pl, opcode);
15960f30cd6SAmit Cohen 
16060f30cd6SAmit Cohen 	err = mlxsw_reg_query(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pddr),
16160f30cd6SAmit Cohen 			      pddr_pl);
16260f30cd6SAmit Cohen 	if (err)
16360f30cd6SAmit Cohen 		return err;
16460f30cd6SAmit Cohen 
16560f30cd6SAmit Cohen 	status_opcode = mlxsw_reg_pddr_trblsh_status_opcode_get(pddr_pl);
16660f30cd6SAmit Cohen 	if (!status_opcode)
16760f30cd6SAmit Cohen 		return -ENODATA;
16860f30cd6SAmit Cohen 
16960f30cd6SAmit Cohen 	for (i = 0; i < ARRAY_SIZE(mlxsw_sp_link_ext_state_opcode_map); i++) {
17060f30cd6SAmit Cohen 		link_ext_state_mapping = mlxsw_sp_link_ext_state_opcode_map[i];
17160f30cd6SAmit Cohen 		if (link_ext_state_mapping.status_opcode == status_opcode) {
17260f30cd6SAmit Cohen 			mlxsw_sp_port_set_link_ext_state(link_ext_state_mapping,
17360f30cd6SAmit Cohen 							 link_ext_state_info);
17460f30cd6SAmit Cohen 			return 0;
17560f30cd6SAmit Cohen 		}
17660f30cd6SAmit Cohen 	}
17760f30cd6SAmit Cohen 
17860f30cd6SAmit Cohen 	return -ENODATA;
17960f30cd6SAmit Cohen }
18060f30cd6SAmit Cohen 
mlxsw_sp_port_get_pauseparam(struct net_device * dev,struct ethtool_pauseparam * pause)181614d509aSAmit Cohen static void mlxsw_sp_port_get_pauseparam(struct net_device *dev,
182614d509aSAmit Cohen 					 struct ethtool_pauseparam *pause)
183614d509aSAmit Cohen {
184614d509aSAmit Cohen 	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
185614d509aSAmit Cohen 
186614d509aSAmit Cohen 	pause->rx_pause = mlxsw_sp_port->link.rx_pause;
187614d509aSAmit Cohen 	pause->tx_pause = mlxsw_sp_port->link.tx_pause;
188614d509aSAmit Cohen }
189614d509aSAmit Cohen 
mlxsw_sp_port_pause_set(struct mlxsw_sp_port * mlxsw_sp_port,struct ethtool_pauseparam * pause)190614d509aSAmit Cohen static int mlxsw_sp_port_pause_set(struct mlxsw_sp_port *mlxsw_sp_port,
191614d509aSAmit Cohen 				   struct ethtool_pauseparam *pause)
192614d509aSAmit Cohen {
193614d509aSAmit Cohen 	char pfcc_pl[MLXSW_REG_PFCC_LEN];
194614d509aSAmit Cohen 
195614d509aSAmit Cohen 	mlxsw_reg_pfcc_pack(pfcc_pl, mlxsw_sp_port->local_port);
196614d509aSAmit Cohen 	mlxsw_reg_pfcc_pprx_set(pfcc_pl, pause->rx_pause);
197614d509aSAmit Cohen 	mlxsw_reg_pfcc_pptx_set(pfcc_pl, pause->tx_pause);
198614d509aSAmit Cohen 
199614d509aSAmit Cohen 	return mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pfcc),
200614d509aSAmit Cohen 			       pfcc_pl);
201614d509aSAmit Cohen }
202614d509aSAmit Cohen 
203b7e07bbdSPetr Machata /* Maximum delay buffer needed in case of PAUSE frames. Similar to PFC delay, but is
204b7e07bbdSPetr Machata  * measured in bytes. Assumes 100m cable and does not take into account MTU.
205b7e07bbdSPetr Machata  */
206b7e07bbdSPetr Machata #define MLXSW_SP_PAUSE_DELAY_BYTES 19476
207b7e07bbdSPetr Machata 
mlxsw_sp_port_set_pauseparam(struct net_device * dev,struct ethtool_pauseparam * pause)208614d509aSAmit Cohen static int mlxsw_sp_port_set_pauseparam(struct net_device *dev,
209614d509aSAmit Cohen 					struct ethtool_pauseparam *pause)
210614d509aSAmit Cohen {
211614d509aSAmit Cohen 	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
212614d509aSAmit Cohen 	bool pause_en = pause->tx_pause || pause->rx_pause;
213b7e07bbdSPetr Machata 	struct mlxsw_sp_hdroom orig_hdroom;
214b7e07bbdSPetr Machata 	struct mlxsw_sp_hdroom hdroom;
215ca21e84eSPetr Machata 	int prio;
216614d509aSAmit Cohen 	int err;
217614d509aSAmit Cohen 
218614d509aSAmit Cohen 	if (mlxsw_sp_port->dcb.pfc && mlxsw_sp_port->dcb.pfc->pfc_en) {
219614d509aSAmit Cohen 		netdev_err(dev, "PFC already enabled on port\n");
220614d509aSAmit Cohen 		return -EINVAL;
221614d509aSAmit Cohen 	}
222614d509aSAmit Cohen 
223614d509aSAmit Cohen 	if (pause->autoneg) {
224614d509aSAmit Cohen 		netdev_err(dev, "PAUSE frames autonegotiation isn't supported\n");
225614d509aSAmit Cohen 		return -EINVAL;
226614d509aSAmit Cohen 	}
227614d509aSAmit Cohen 
228b7e07bbdSPetr Machata 	orig_hdroom = *mlxsw_sp_port->hdroom;
229b7e07bbdSPetr Machata 
230b7e07bbdSPetr Machata 	hdroom = orig_hdroom;
231b7e07bbdSPetr Machata 	if (pause_en)
232b7e07bbdSPetr Machata 		hdroom.delay_bytes = MLXSW_SP_PAUSE_DELAY_BYTES;
233b7e07bbdSPetr Machata 	else
234b7e07bbdSPetr Machata 		hdroom.delay_bytes = 0;
235b7e07bbdSPetr Machata 
236ca21e84eSPetr Machata 	for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++)
237ca21e84eSPetr Machata 		hdroom.prios.prio[prio].lossy = !pause_en;
238ca21e84eSPetr Machata 
239ca21e84eSPetr Machata 	mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom);
2402d9f703fSPetr Machata 	mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
241ca21e84eSPetr Machata 
2422d9f703fSPetr Machata 	err = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
243614d509aSAmit Cohen 	if (err) {
244614d509aSAmit Cohen 		netdev_err(dev, "Failed to configure port's headroom\n");
245614d509aSAmit Cohen 		return err;
246614d509aSAmit Cohen 	}
247614d509aSAmit Cohen 
248614d509aSAmit Cohen 	err = mlxsw_sp_port_pause_set(mlxsw_sp_port, pause);
249614d509aSAmit Cohen 	if (err) {
250614d509aSAmit Cohen 		netdev_err(dev, "Failed to set PAUSE parameters\n");
251614d509aSAmit Cohen 		goto err_port_pause_configure;
252614d509aSAmit Cohen 	}
253614d509aSAmit Cohen 
254614d509aSAmit Cohen 	mlxsw_sp_port->link.rx_pause = pause->rx_pause;
255614d509aSAmit Cohen 	mlxsw_sp_port->link.tx_pause = pause->tx_pause;
256614d509aSAmit Cohen 
257614d509aSAmit Cohen 	return 0;
258614d509aSAmit Cohen 
259614d509aSAmit Cohen err_port_pause_configure:
2602d9f703fSPetr Machata 	mlxsw_sp_hdroom_configure(mlxsw_sp_port, &orig_hdroom);
261614d509aSAmit Cohen 	return err;
262614d509aSAmit Cohen }
263614d509aSAmit Cohen 
264614d509aSAmit Cohen struct mlxsw_sp_port_hw_stats {
265614d509aSAmit Cohen 	char str[ETH_GSTRING_LEN];
266614d509aSAmit Cohen 	u64 (*getter)(const char *payload);
267614d509aSAmit Cohen 	bool cells_bytes;
268614d509aSAmit Cohen };
269614d509aSAmit Cohen 
270614d509aSAmit Cohen static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_stats[] = {
271614d509aSAmit Cohen 	{
272614d509aSAmit Cohen 		.str = "a_frames_transmitted_ok",
273614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_a_frames_transmitted_ok_get,
274614d509aSAmit Cohen 	},
275614d509aSAmit Cohen 	{
276614d509aSAmit Cohen 		.str = "a_frames_received_ok",
277614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_a_frames_received_ok_get,
278614d509aSAmit Cohen 	},
279614d509aSAmit Cohen 	{
280614d509aSAmit Cohen 		.str = "a_frame_check_sequence_errors",
281614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_a_frame_check_sequence_errors_get,
282614d509aSAmit Cohen 	},
283614d509aSAmit Cohen 	{
284614d509aSAmit Cohen 		.str = "a_alignment_errors",
285614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_a_alignment_errors_get,
286614d509aSAmit Cohen 	},
287614d509aSAmit Cohen 	{
288614d509aSAmit Cohen 		.str = "a_octets_transmitted_ok",
289614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_a_octets_transmitted_ok_get,
290614d509aSAmit Cohen 	},
291614d509aSAmit Cohen 	{
292614d509aSAmit Cohen 		.str = "a_octets_received_ok",
293614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_a_octets_received_ok_get,
294614d509aSAmit Cohen 	},
295614d509aSAmit Cohen 	{
296614d509aSAmit Cohen 		.str = "a_multicast_frames_xmitted_ok",
297614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_a_multicast_frames_xmitted_ok_get,
298614d509aSAmit Cohen 	},
299614d509aSAmit Cohen 	{
300614d509aSAmit Cohen 		.str = "a_broadcast_frames_xmitted_ok",
301614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_a_broadcast_frames_xmitted_ok_get,
302614d509aSAmit Cohen 	},
303614d509aSAmit Cohen 	{
304614d509aSAmit Cohen 		.str = "a_multicast_frames_received_ok",
305614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_a_multicast_frames_received_ok_get,
306614d509aSAmit Cohen 	},
307614d509aSAmit Cohen 	{
308614d509aSAmit Cohen 		.str = "a_broadcast_frames_received_ok",
309614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_a_broadcast_frames_received_ok_get,
310614d509aSAmit Cohen 	},
311614d509aSAmit Cohen 	{
312614d509aSAmit Cohen 		.str = "a_in_range_length_errors",
313614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_a_in_range_length_errors_get,
314614d509aSAmit Cohen 	},
315614d509aSAmit Cohen 	{
316614d509aSAmit Cohen 		.str = "a_out_of_range_length_field",
317614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_a_out_of_range_length_field_get,
318614d509aSAmit Cohen 	},
319614d509aSAmit Cohen 	{
320614d509aSAmit Cohen 		.str = "a_frame_too_long_errors",
321614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_a_frame_too_long_errors_get,
322614d509aSAmit Cohen 	},
323614d509aSAmit Cohen 	{
324614d509aSAmit Cohen 		.str = "a_symbol_error_during_carrier",
325614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_a_symbol_error_during_carrier_get,
326614d509aSAmit Cohen 	},
327614d509aSAmit Cohen 	{
328614d509aSAmit Cohen 		.str = "a_mac_control_frames_transmitted",
329614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_a_mac_control_frames_transmitted_get,
330614d509aSAmit Cohen 	},
331614d509aSAmit Cohen 	{
332614d509aSAmit Cohen 		.str = "a_mac_control_frames_received",
333614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_a_mac_control_frames_received_get,
334614d509aSAmit Cohen 	},
335614d509aSAmit Cohen 	{
336614d509aSAmit Cohen 		.str = "a_unsupported_opcodes_received",
337614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_a_unsupported_opcodes_received_get,
338614d509aSAmit Cohen 	},
339614d509aSAmit Cohen 	{
340614d509aSAmit Cohen 		.str = "a_pause_mac_ctrl_frames_received",
341614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_a_pause_mac_ctrl_frames_received_get,
342614d509aSAmit Cohen 	},
343614d509aSAmit Cohen 	{
344614d509aSAmit Cohen 		.str = "a_pause_mac_ctrl_frames_xmitted",
345614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_a_pause_mac_ctrl_frames_transmitted_get,
346614d509aSAmit Cohen 	},
347614d509aSAmit Cohen };
348614d509aSAmit Cohen 
349614d509aSAmit Cohen #define MLXSW_SP_PORT_HW_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_hw_stats)
350614d509aSAmit Cohen 
351614d509aSAmit Cohen static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_rfc_2863_stats[] = {
352614d509aSAmit Cohen 	{
353614d509aSAmit Cohen 		.str = "if_in_discards",
354614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_if_in_discards_get,
355614d509aSAmit Cohen 	},
356614d509aSAmit Cohen 	{
357614d509aSAmit Cohen 		.str = "if_out_discards",
358614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_if_out_discards_get,
359614d509aSAmit Cohen 	},
360614d509aSAmit Cohen 	{
361614d509aSAmit Cohen 		.str = "if_out_errors",
362614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_if_out_errors_get,
363614d509aSAmit Cohen 	},
364614d509aSAmit Cohen };
365614d509aSAmit Cohen 
366614d509aSAmit Cohen #define MLXSW_SP_PORT_HW_RFC_2863_STATS_LEN \
367614d509aSAmit Cohen 	ARRAY_SIZE(mlxsw_sp_port_hw_rfc_2863_stats)
368614d509aSAmit Cohen 
369614d509aSAmit Cohen static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_rfc_2819_stats[] = {
370614d509aSAmit Cohen 	{
371614d509aSAmit Cohen 		.str = "ether_stats_undersize_pkts",
372614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_ether_stats_undersize_pkts_get,
373614d509aSAmit Cohen 	},
374614d509aSAmit Cohen 	{
375614d509aSAmit Cohen 		.str = "ether_stats_oversize_pkts",
376614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_ether_stats_oversize_pkts_get,
377614d509aSAmit Cohen 	},
378614d509aSAmit Cohen 	{
379614d509aSAmit Cohen 		.str = "ether_stats_fragments",
380614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_ether_stats_fragments_get,
381614d509aSAmit Cohen 	},
382614d509aSAmit Cohen 	{
383614d509aSAmit Cohen 		.str = "ether_pkts64octets",
384614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_ether_stats_pkts64octets_get,
385614d509aSAmit Cohen 	},
386614d509aSAmit Cohen 	{
387614d509aSAmit Cohen 		.str = "ether_pkts65to127octets",
388614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_ether_stats_pkts65to127octets_get,
389614d509aSAmit Cohen 	},
390614d509aSAmit Cohen 	{
391614d509aSAmit Cohen 		.str = "ether_pkts128to255octets",
392614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_ether_stats_pkts128to255octets_get,
393614d509aSAmit Cohen 	},
394614d509aSAmit Cohen 	{
395614d509aSAmit Cohen 		.str = "ether_pkts256to511octets",
396614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_ether_stats_pkts256to511octets_get,
397614d509aSAmit Cohen 	},
398614d509aSAmit Cohen 	{
399614d509aSAmit Cohen 		.str = "ether_pkts512to1023octets",
400614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_ether_stats_pkts512to1023octets_get,
401614d509aSAmit Cohen 	},
402614d509aSAmit Cohen 	{
403614d509aSAmit Cohen 		.str = "ether_pkts1024to1518octets",
404614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_ether_stats_pkts1024to1518octets_get,
405614d509aSAmit Cohen 	},
406614d509aSAmit Cohen 	{
407614d509aSAmit Cohen 		.str = "ether_pkts1519to2047octets",
408614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_ether_stats_pkts1519to2047octets_get,
409614d509aSAmit Cohen 	},
410614d509aSAmit Cohen 	{
411614d509aSAmit Cohen 		.str = "ether_pkts2048to4095octets",
412614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_ether_stats_pkts2048to4095octets_get,
413614d509aSAmit Cohen 	},
414614d509aSAmit Cohen 	{
415614d509aSAmit Cohen 		.str = "ether_pkts4096to8191octets",
416614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_ether_stats_pkts4096to8191octets_get,
417614d509aSAmit Cohen 	},
418614d509aSAmit Cohen 	{
419614d509aSAmit Cohen 		.str = "ether_pkts8192to10239octets",
420614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_ether_stats_pkts8192to10239octets_get,
421614d509aSAmit Cohen 	},
422614d509aSAmit Cohen };
423614d509aSAmit Cohen 
424614d509aSAmit Cohen #define MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN \
425614d509aSAmit Cohen 	ARRAY_SIZE(mlxsw_sp_port_hw_rfc_2819_stats)
426614d509aSAmit Cohen 
427614d509aSAmit Cohen static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_rfc_3635_stats[] = {
428614d509aSAmit Cohen 	{
429614d509aSAmit Cohen 		.str = "dot3stats_fcs_errors",
430614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_dot3stats_fcs_errors_get,
431614d509aSAmit Cohen 	},
432614d509aSAmit Cohen 	{
433614d509aSAmit Cohen 		.str = "dot3stats_symbol_errors",
434614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_dot3stats_symbol_errors_get,
435614d509aSAmit Cohen 	},
436614d509aSAmit Cohen 	{
437614d509aSAmit Cohen 		.str = "dot3control_in_unknown_opcodes",
438614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_dot3control_in_unknown_opcodes_get,
439614d509aSAmit Cohen 	},
440614d509aSAmit Cohen 	{
441614d509aSAmit Cohen 		.str = "dot3in_pause_frames",
442614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_dot3in_pause_frames_get,
443614d509aSAmit Cohen 	},
444614d509aSAmit Cohen };
445614d509aSAmit Cohen 
446614d509aSAmit Cohen #define MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN \
447614d509aSAmit Cohen 	ARRAY_SIZE(mlxsw_sp_port_hw_rfc_3635_stats)
448614d509aSAmit Cohen 
449614d509aSAmit Cohen static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_ext_stats[] = {
450614d509aSAmit Cohen 	{
451614d509aSAmit Cohen 		.str = "ecn_marked",
452614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_ecn_marked_get,
453614d509aSAmit Cohen 	},
454614d509aSAmit Cohen };
455614d509aSAmit Cohen 
456614d509aSAmit Cohen #define MLXSW_SP_PORT_HW_EXT_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_hw_ext_stats)
457614d509aSAmit Cohen 
458614d509aSAmit Cohen static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_discard_stats[] = {
459614d509aSAmit Cohen 	{
460614d509aSAmit Cohen 		.str = "discard_ingress_general",
461614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_ingress_general_get,
462614d509aSAmit Cohen 	},
463614d509aSAmit Cohen 	{
464614d509aSAmit Cohen 		.str = "discard_ingress_policy_engine",
465614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_ingress_policy_engine_get,
466614d509aSAmit Cohen 	},
467614d509aSAmit Cohen 	{
468614d509aSAmit Cohen 		.str = "discard_ingress_vlan_membership",
469614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_ingress_vlan_membership_get,
470614d509aSAmit Cohen 	},
471614d509aSAmit Cohen 	{
472614d509aSAmit Cohen 		.str = "discard_ingress_tag_frame_type",
473614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_ingress_tag_frame_type_get,
474614d509aSAmit Cohen 	},
475614d509aSAmit Cohen 	{
476614d509aSAmit Cohen 		.str = "discard_egress_vlan_membership",
477614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_egress_vlan_membership_get,
478614d509aSAmit Cohen 	},
479614d509aSAmit Cohen 	{
480614d509aSAmit Cohen 		.str = "discard_loopback_filter",
481614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_loopback_filter_get,
482614d509aSAmit Cohen 	},
483614d509aSAmit Cohen 	{
484614d509aSAmit Cohen 		.str = "discard_egress_general",
485614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_egress_general_get,
486614d509aSAmit Cohen 	},
487614d509aSAmit Cohen 	{
488614d509aSAmit Cohen 		.str = "discard_egress_hoq",
489614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_egress_hoq_get,
490614d509aSAmit Cohen 	},
491614d509aSAmit Cohen 	{
492614d509aSAmit Cohen 		.str = "discard_egress_policy_engine",
493614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_egress_policy_engine_get,
494614d509aSAmit Cohen 	},
495614d509aSAmit Cohen 	{
496614d509aSAmit Cohen 		.str = "discard_ingress_tx_link_down",
497614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_ingress_tx_link_down_get,
498614d509aSAmit Cohen 	},
499614d509aSAmit Cohen 	{
500614d509aSAmit Cohen 		.str = "discard_egress_stp_filter",
501614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_egress_stp_filter_get,
502614d509aSAmit Cohen 	},
503614d509aSAmit Cohen 	{
504614d509aSAmit Cohen 		.str = "discard_egress_sll",
505614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_egress_sll_get,
506614d509aSAmit Cohen 	},
507614d509aSAmit Cohen };
508614d509aSAmit Cohen 
509614d509aSAmit Cohen #define MLXSW_SP_PORT_HW_DISCARD_STATS_LEN \
510614d509aSAmit Cohen 	ARRAY_SIZE(mlxsw_sp_port_hw_discard_stats)
511614d509aSAmit Cohen 
512614d509aSAmit Cohen static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_prio_stats[] = {
513614d509aSAmit Cohen 	{
514614d509aSAmit Cohen 		.str = "rx_octets_prio",
515614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_rx_octets_get,
516614d509aSAmit Cohen 	},
517614d509aSAmit Cohen 	{
518614d509aSAmit Cohen 		.str = "rx_frames_prio",
519614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_rx_frames_get,
520614d509aSAmit Cohen 	},
521614d509aSAmit Cohen 	{
522614d509aSAmit Cohen 		.str = "tx_octets_prio",
523614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_tx_octets_get,
524614d509aSAmit Cohen 	},
525614d509aSAmit Cohen 	{
526614d509aSAmit Cohen 		.str = "tx_frames_prio",
527614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_tx_frames_get,
528614d509aSAmit Cohen 	},
529614d509aSAmit Cohen 	{
530614d509aSAmit Cohen 		.str = "rx_pause_prio",
531614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_rx_pause_get,
532614d509aSAmit Cohen 	},
533614d509aSAmit Cohen 	{
534614d509aSAmit Cohen 		.str = "rx_pause_duration_prio",
535614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_rx_pause_duration_get,
536614d509aSAmit Cohen 	},
537614d509aSAmit Cohen 	{
538614d509aSAmit Cohen 		.str = "tx_pause_prio",
539614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_tx_pause_get,
540614d509aSAmit Cohen 	},
541614d509aSAmit Cohen 	{
542614d509aSAmit Cohen 		.str = "tx_pause_duration_prio",
543614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_tx_pause_duration_get,
544614d509aSAmit Cohen 	},
545614d509aSAmit Cohen };
546614d509aSAmit Cohen 
547614d509aSAmit Cohen #define MLXSW_SP_PORT_HW_PRIO_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_hw_prio_stats)
548614d509aSAmit Cohen 
549614d509aSAmit Cohen static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_tc_stats[] = {
550614d509aSAmit Cohen 	{
551614d509aSAmit Cohen 		.str = "tc_transmit_queue_tc",
552614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_tc_transmit_queue_get,
553614d509aSAmit Cohen 		.cells_bytes = true,
554614d509aSAmit Cohen 	},
555614d509aSAmit Cohen 	{
556614d509aSAmit Cohen 		.str = "tc_no_buffer_discard_uc_tc",
557614d509aSAmit Cohen 		.getter = mlxsw_reg_ppcnt_tc_no_buffer_discard_uc_get,
558614d509aSAmit Cohen 	},
559614d509aSAmit Cohen };
560614d509aSAmit Cohen 
561614d509aSAmit Cohen #define MLXSW_SP_PORT_HW_TC_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_hw_tc_stats)
562614d509aSAmit Cohen 
56369f6d4eeSAmit Cohen struct mlxsw_sp_port_stats {
56469f6d4eeSAmit Cohen 	char str[ETH_GSTRING_LEN];
56569f6d4eeSAmit Cohen 	u64 (*getter)(struct mlxsw_sp_port *mlxsw_sp_port);
56669f6d4eeSAmit Cohen };
56769f6d4eeSAmit Cohen 
56869f6d4eeSAmit Cohen static u64
mlxsw_sp_port_get_transceiver_overheat_stats(struct mlxsw_sp_port * mlxsw_sp_port)56969f6d4eeSAmit Cohen mlxsw_sp_port_get_transceiver_overheat_stats(struct mlxsw_sp_port *mlxsw_sp_port)
57069f6d4eeSAmit Cohen {
57169f6d4eeSAmit Cohen 	struct mlxsw_core *mlxsw_core = mlxsw_sp_port->mlxsw_sp->core;
5726445eef0SJiri Pirko 	u8 slot_index = mlxsw_sp_port->mapping.slot_index;
5736445eef0SJiri Pirko 	u8 module = mlxsw_sp_port->mapping.module;
57469f6d4eeSAmit Cohen 	u64 stats;
57569f6d4eeSAmit Cohen 	int err;
57669f6d4eeSAmit Cohen 
5776445eef0SJiri Pirko 	err = mlxsw_env_module_overheat_counter_get(mlxsw_core, slot_index,
5786445eef0SJiri Pirko 						    module, &stats);
57969f6d4eeSAmit Cohen 	if (err)
58069f6d4eeSAmit Cohen 		return mlxsw_sp_port->module_overheat_initial_val;
58169f6d4eeSAmit Cohen 
58269f6d4eeSAmit Cohen 	return stats - mlxsw_sp_port->module_overheat_initial_val;
58369f6d4eeSAmit Cohen }
58469f6d4eeSAmit Cohen 
58569f6d4eeSAmit Cohen static struct mlxsw_sp_port_stats mlxsw_sp_port_transceiver_stats[] = {
58669f6d4eeSAmit Cohen 	{
58769f6d4eeSAmit Cohen 		.str = "transceiver_overheat",
58869f6d4eeSAmit Cohen 		.getter = mlxsw_sp_port_get_transceiver_overheat_stats,
58969f6d4eeSAmit Cohen 	},
59069f6d4eeSAmit Cohen };
59169f6d4eeSAmit Cohen 
59269f6d4eeSAmit Cohen #define MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_transceiver_stats)
59369f6d4eeSAmit Cohen 
594614d509aSAmit Cohen #define MLXSW_SP_PORT_ETHTOOL_STATS_LEN (MLXSW_SP_PORT_HW_STATS_LEN + \
595614d509aSAmit Cohen 					 MLXSW_SP_PORT_HW_RFC_2863_STATS_LEN + \
596614d509aSAmit Cohen 					 MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN + \
597614d509aSAmit Cohen 					 MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN + \
598614d509aSAmit Cohen 					 MLXSW_SP_PORT_HW_EXT_STATS_LEN + \
599614d509aSAmit Cohen 					 MLXSW_SP_PORT_HW_DISCARD_STATS_LEN + \
600614d509aSAmit Cohen 					 (MLXSW_SP_PORT_HW_PRIO_STATS_LEN * \
601614d509aSAmit Cohen 					  IEEE_8021QAZ_MAX_TCS) + \
602614d509aSAmit Cohen 					 (MLXSW_SP_PORT_HW_TC_STATS_LEN * \
60369f6d4eeSAmit Cohen 					  TC_MAX_QUEUE) + \
60469f6d4eeSAmit Cohen 					  MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN)
605614d509aSAmit Cohen 
mlxsw_sp_port_get_prio_strings(u8 ** p,int prio)606614d509aSAmit Cohen static void mlxsw_sp_port_get_prio_strings(u8 **p, int prio)
607614d509aSAmit Cohen {
608614d509aSAmit Cohen 	int i;
609614d509aSAmit Cohen 
610614d509aSAmit Cohen 	for (i = 0; i < MLXSW_SP_PORT_HW_PRIO_STATS_LEN; i++) {
611614d509aSAmit Cohen 		snprintf(*p, ETH_GSTRING_LEN, "%.29s_%.1d",
612614d509aSAmit Cohen 			 mlxsw_sp_port_hw_prio_stats[i].str, prio);
613614d509aSAmit Cohen 		*p += ETH_GSTRING_LEN;
614614d509aSAmit Cohen 	}
615614d509aSAmit Cohen }
616614d509aSAmit Cohen 
mlxsw_sp_port_get_tc_strings(u8 ** p,int tc)617614d509aSAmit Cohen static void mlxsw_sp_port_get_tc_strings(u8 **p, int tc)
618614d509aSAmit Cohen {
619614d509aSAmit Cohen 	int i;
620614d509aSAmit Cohen 
621614d509aSAmit Cohen 	for (i = 0; i < MLXSW_SP_PORT_HW_TC_STATS_LEN; i++) {
622614d509aSAmit Cohen 		snprintf(*p, ETH_GSTRING_LEN, "%.29s_%.1d",
623614d509aSAmit Cohen 			 mlxsw_sp_port_hw_tc_stats[i].str, tc);
624614d509aSAmit Cohen 		*p += ETH_GSTRING_LEN;
625614d509aSAmit Cohen 	}
626614d509aSAmit Cohen }
627614d509aSAmit Cohen 
mlxsw_sp_port_get_strings(struct net_device * dev,u32 stringset,u8 * data)628614d509aSAmit Cohen static void mlxsw_sp_port_get_strings(struct net_device *dev,
629614d509aSAmit Cohen 				      u32 stringset, u8 *data)
630614d509aSAmit Cohen {
631614d509aSAmit Cohen 	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
632614d509aSAmit Cohen 	u8 *p = data;
633614d509aSAmit Cohen 	int i;
634614d509aSAmit Cohen 
635614d509aSAmit Cohen 	switch (stringset) {
636614d509aSAmit Cohen 	case ETH_SS_STATS:
637614d509aSAmit Cohen 		for (i = 0; i < MLXSW_SP_PORT_HW_STATS_LEN; i++) {
638614d509aSAmit Cohen 			memcpy(p, mlxsw_sp_port_hw_stats[i].str,
639614d509aSAmit Cohen 			       ETH_GSTRING_LEN);
640614d509aSAmit Cohen 			p += ETH_GSTRING_LEN;
641614d509aSAmit Cohen 		}
642614d509aSAmit Cohen 
643614d509aSAmit Cohen 		for (i = 0; i < MLXSW_SP_PORT_HW_RFC_2863_STATS_LEN; i++) {
644614d509aSAmit Cohen 			memcpy(p, mlxsw_sp_port_hw_rfc_2863_stats[i].str,
645614d509aSAmit Cohen 			       ETH_GSTRING_LEN);
646614d509aSAmit Cohen 			p += ETH_GSTRING_LEN;
647614d509aSAmit Cohen 		}
648614d509aSAmit Cohen 
649614d509aSAmit Cohen 		for (i = 0; i < MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN; i++) {
650614d509aSAmit Cohen 			memcpy(p, mlxsw_sp_port_hw_rfc_2819_stats[i].str,
651614d509aSAmit Cohen 			       ETH_GSTRING_LEN);
652614d509aSAmit Cohen 			p += ETH_GSTRING_LEN;
653614d509aSAmit Cohen 		}
654614d509aSAmit Cohen 
655614d509aSAmit Cohen 		for (i = 0; i < MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN; i++) {
656614d509aSAmit Cohen 			memcpy(p, mlxsw_sp_port_hw_rfc_3635_stats[i].str,
657614d509aSAmit Cohen 			       ETH_GSTRING_LEN);
658614d509aSAmit Cohen 			p += ETH_GSTRING_LEN;
659614d509aSAmit Cohen 		}
660614d509aSAmit Cohen 
661614d509aSAmit Cohen 		for (i = 0; i < MLXSW_SP_PORT_HW_EXT_STATS_LEN; i++) {
662614d509aSAmit Cohen 			memcpy(p, mlxsw_sp_port_hw_ext_stats[i].str,
663614d509aSAmit Cohen 			       ETH_GSTRING_LEN);
664614d509aSAmit Cohen 			p += ETH_GSTRING_LEN;
665614d509aSAmit Cohen 		}
666614d509aSAmit Cohen 
667614d509aSAmit Cohen 		for (i = 0; i < MLXSW_SP_PORT_HW_DISCARD_STATS_LEN; i++) {
668614d509aSAmit Cohen 			memcpy(p, mlxsw_sp_port_hw_discard_stats[i].str,
669614d509aSAmit Cohen 			       ETH_GSTRING_LEN);
670614d509aSAmit Cohen 			p += ETH_GSTRING_LEN;
671614d509aSAmit Cohen 		}
672614d509aSAmit Cohen 
673614d509aSAmit Cohen 		for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
674614d509aSAmit Cohen 			mlxsw_sp_port_get_prio_strings(&p, i);
675614d509aSAmit Cohen 
676614d509aSAmit Cohen 		for (i = 0; i < TC_MAX_QUEUE; i++)
677614d509aSAmit Cohen 			mlxsw_sp_port_get_tc_strings(&p, i);
678614d509aSAmit Cohen 
679614d509aSAmit Cohen 		mlxsw_sp_port->mlxsw_sp->ptp_ops->get_stats_strings(&p);
68069f6d4eeSAmit Cohen 
68169f6d4eeSAmit Cohen 		for (i = 0; i < MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN; i++) {
68269f6d4eeSAmit Cohen 			memcpy(p, mlxsw_sp_port_transceiver_stats[i].str,
68369f6d4eeSAmit Cohen 			       ETH_GSTRING_LEN);
68469f6d4eeSAmit Cohen 			p += ETH_GSTRING_LEN;
68569f6d4eeSAmit Cohen 		}
686614d509aSAmit Cohen 		break;
687614d509aSAmit Cohen 	}
688614d509aSAmit Cohen }
689614d509aSAmit Cohen 
mlxsw_sp_port_set_phys_id(struct net_device * dev,enum ethtool_phys_id_state state)690614d509aSAmit Cohen static int mlxsw_sp_port_set_phys_id(struct net_device *dev,
691614d509aSAmit Cohen 				     enum ethtool_phys_id_state state)
692614d509aSAmit Cohen {
693614d509aSAmit Cohen 	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
694614d509aSAmit Cohen 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
695614d509aSAmit Cohen 	char mlcr_pl[MLXSW_REG_MLCR_LEN];
696614d509aSAmit Cohen 	bool active;
697614d509aSAmit Cohen 
698614d509aSAmit Cohen 	switch (state) {
699614d509aSAmit Cohen 	case ETHTOOL_ID_ACTIVE:
700614d509aSAmit Cohen 		active = true;
701614d509aSAmit Cohen 		break;
702614d509aSAmit Cohen 	case ETHTOOL_ID_INACTIVE:
703614d509aSAmit Cohen 		active = false;
704614d509aSAmit Cohen 		break;
705614d509aSAmit Cohen 	default:
706614d509aSAmit Cohen 		return -EOPNOTSUPP;
707614d509aSAmit Cohen 	}
708614d509aSAmit Cohen 
709614d509aSAmit Cohen 	mlxsw_reg_mlcr_pack(mlcr_pl, mlxsw_sp_port->local_port, active);
710614d509aSAmit Cohen 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mlcr), mlcr_pl);
711614d509aSAmit Cohen }
712614d509aSAmit Cohen 
713614d509aSAmit Cohen static int
mlxsw_sp_get_hw_stats_by_group(struct mlxsw_sp_port_hw_stats ** p_hw_stats,int * p_len,enum mlxsw_reg_ppcnt_grp grp)714614d509aSAmit Cohen mlxsw_sp_get_hw_stats_by_group(struct mlxsw_sp_port_hw_stats **p_hw_stats,
715614d509aSAmit Cohen 			       int *p_len, enum mlxsw_reg_ppcnt_grp grp)
716614d509aSAmit Cohen {
717614d509aSAmit Cohen 	switch (grp) {
718614d509aSAmit Cohen 	case MLXSW_REG_PPCNT_IEEE_8023_CNT:
719614d509aSAmit Cohen 		*p_hw_stats = mlxsw_sp_port_hw_stats;
720614d509aSAmit Cohen 		*p_len = MLXSW_SP_PORT_HW_STATS_LEN;
721614d509aSAmit Cohen 		break;
722614d509aSAmit Cohen 	case MLXSW_REG_PPCNT_RFC_2863_CNT:
723614d509aSAmit Cohen 		*p_hw_stats = mlxsw_sp_port_hw_rfc_2863_stats;
724614d509aSAmit Cohen 		*p_len = MLXSW_SP_PORT_HW_RFC_2863_STATS_LEN;
725614d509aSAmit Cohen 		break;
726614d509aSAmit Cohen 	case MLXSW_REG_PPCNT_RFC_2819_CNT:
727614d509aSAmit Cohen 		*p_hw_stats = mlxsw_sp_port_hw_rfc_2819_stats;
728614d509aSAmit Cohen 		*p_len = MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN;
729614d509aSAmit Cohen 		break;
730614d509aSAmit Cohen 	case MLXSW_REG_PPCNT_RFC_3635_CNT:
731614d509aSAmit Cohen 		*p_hw_stats = mlxsw_sp_port_hw_rfc_3635_stats;
732614d509aSAmit Cohen 		*p_len = MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN;
733614d509aSAmit Cohen 		break;
734614d509aSAmit Cohen 	case MLXSW_REG_PPCNT_EXT_CNT:
735614d509aSAmit Cohen 		*p_hw_stats = mlxsw_sp_port_hw_ext_stats;
736614d509aSAmit Cohen 		*p_len = MLXSW_SP_PORT_HW_EXT_STATS_LEN;
737614d509aSAmit Cohen 		break;
738614d509aSAmit Cohen 	case MLXSW_REG_PPCNT_DISCARD_CNT:
739614d509aSAmit Cohen 		*p_hw_stats = mlxsw_sp_port_hw_discard_stats;
740614d509aSAmit Cohen 		*p_len = MLXSW_SP_PORT_HW_DISCARD_STATS_LEN;
741614d509aSAmit Cohen 		break;
742614d509aSAmit Cohen 	case MLXSW_REG_PPCNT_PRIO_CNT:
743614d509aSAmit Cohen 		*p_hw_stats = mlxsw_sp_port_hw_prio_stats;
744614d509aSAmit Cohen 		*p_len = MLXSW_SP_PORT_HW_PRIO_STATS_LEN;
745614d509aSAmit Cohen 		break;
746614d509aSAmit Cohen 	case MLXSW_REG_PPCNT_TC_CNT:
747614d509aSAmit Cohen 		*p_hw_stats = mlxsw_sp_port_hw_tc_stats;
748614d509aSAmit Cohen 		*p_len = MLXSW_SP_PORT_HW_TC_STATS_LEN;
749614d509aSAmit Cohen 		break;
750614d509aSAmit Cohen 	default:
751614d509aSAmit Cohen 		WARN_ON(1);
752614d509aSAmit Cohen 		return -EOPNOTSUPP;
753614d509aSAmit Cohen 	}
754614d509aSAmit Cohen 	return 0;
755614d509aSAmit Cohen }
756614d509aSAmit Cohen 
__mlxsw_sp_port_get_stats(struct net_device * dev,enum mlxsw_reg_ppcnt_grp grp,int prio,u64 * data,int data_index)757614d509aSAmit Cohen static void __mlxsw_sp_port_get_stats(struct net_device *dev,
758614d509aSAmit Cohen 				      enum mlxsw_reg_ppcnt_grp grp, int prio,
759614d509aSAmit Cohen 				      u64 *data, int data_index)
760614d509aSAmit Cohen {
761614d509aSAmit Cohen 	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
762614d509aSAmit Cohen 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
763614d509aSAmit Cohen 	struct mlxsw_sp_port_hw_stats *hw_stats;
764614d509aSAmit Cohen 	char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
765614d509aSAmit Cohen 	int i, len;
766614d509aSAmit Cohen 	int err;
767614d509aSAmit Cohen 
768614d509aSAmit Cohen 	err = mlxsw_sp_get_hw_stats_by_group(&hw_stats, &len, grp);
769614d509aSAmit Cohen 	if (err)
770614d509aSAmit Cohen 		return;
771614d509aSAmit Cohen 	mlxsw_sp_port_get_stats_raw(dev, grp, prio, ppcnt_pl);
772614d509aSAmit Cohen 	for (i = 0; i < len; i++) {
773614d509aSAmit Cohen 		data[data_index + i] = hw_stats[i].getter(ppcnt_pl);
774614d509aSAmit Cohen 		if (!hw_stats[i].cells_bytes)
775614d509aSAmit Cohen 			continue;
776614d509aSAmit Cohen 		data[data_index + i] = mlxsw_sp_cells_bytes(mlxsw_sp,
777614d509aSAmit Cohen 							    data[data_index + i]);
778614d509aSAmit Cohen 	}
779614d509aSAmit Cohen }
780614d509aSAmit Cohen 
__mlxsw_sp_port_get_env_stats(struct net_device * dev,u64 * data,int data_index,struct mlxsw_sp_port_stats * port_stats,int len)78169f6d4eeSAmit Cohen static void __mlxsw_sp_port_get_env_stats(struct net_device *dev, u64 *data, int data_index,
78269f6d4eeSAmit Cohen 					  struct mlxsw_sp_port_stats *port_stats,
78369f6d4eeSAmit Cohen 					  int len)
78469f6d4eeSAmit Cohen {
78569f6d4eeSAmit Cohen 	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
78669f6d4eeSAmit Cohen 	int i;
78769f6d4eeSAmit Cohen 
78869f6d4eeSAmit Cohen 	for (i = 0; i < len; i++)
78969f6d4eeSAmit Cohen 		data[data_index + i] = port_stats[i].getter(mlxsw_sp_port);
79069f6d4eeSAmit Cohen }
79169f6d4eeSAmit Cohen 
mlxsw_sp_port_get_stats(struct net_device * dev,struct ethtool_stats * stats,u64 * data)792614d509aSAmit Cohen static void mlxsw_sp_port_get_stats(struct net_device *dev,
793614d509aSAmit Cohen 				    struct ethtool_stats *stats, u64 *data)
794614d509aSAmit Cohen {
795614d509aSAmit Cohen 	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
796614d509aSAmit Cohen 	int i, data_index = 0;
797614d509aSAmit Cohen 
798614d509aSAmit Cohen 	/* IEEE 802.3 Counters */
799614d509aSAmit Cohen 	__mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT, 0,
800614d509aSAmit Cohen 				  data, data_index);
801614d509aSAmit Cohen 	data_index = MLXSW_SP_PORT_HW_STATS_LEN;
802614d509aSAmit Cohen 
803614d509aSAmit Cohen 	/* RFC 2863 Counters */
804614d509aSAmit Cohen 	__mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_RFC_2863_CNT, 0,
805614d509aSAmit Cohen 				  data, data_index);
806614d509aSAmit Cohen 	data_index += MLXSW_SP_PORT_HW_RFC_2863_STATS_LEN;
807614d509aSAmit Cohen 
808614d509aSAmit Cohen 	/* RFC 2819 Counters */
809614d509aSAmit Cohen 	__mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_RFC_2819_CNT, 0,
810614d509aSAmit Cohen 				  data, data_index);
811614d509aSAmit Cohen 	data_index += MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN;
812614d509aSAmit Cohen 
813614d509aSAmit Cohen 	/* RFC 3635 Counters */
814614d509aSAmit Cohen 	__mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_RFC_3635_CNT, 0,
815614d509aSAmit Cohen 				  data, data_index);
816614d509aSAmit Cohen 	data_index += MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN;
817614d509aSAmit Cohen 
818614d509aSAmit Cohen 	/* Extended Counters */
819614d509aSAmit Cohen 	__mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_EXT_CNT, 0,
820614d509aSAmit Cohen 				  data, data_index);
821614d509aSAmit Cohen 	data_index += MLXSW_SP_PORT_HW_EXT_STATS_LEN;
822614d509aSAmit Cohen 
823614d509aSAmit Cohen 	/* Discard Counters */
824614d509aSAmit Cohen 	__mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_DISCARD_CNT, 0,
825614d509aSAmit Cohen 				  data, data_index);
826614d509aSAmit Cohen 	data_index += MLXSW_SP_PORT_HW_DISCARD_STATS_LEN;
827614d509aSAmit Cohen 
828614d509aSAmit Cohen 	/* Per-Priority Counters */
829614d509aSAmit Cohen 	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
830614d509aSAmit Cohen 		__mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_PRIO_CNT, i,
831614d509aSAmit Cohen 					  data, data_index);
832614d509aSAmit Cohen 		data_index += MLXSW_SP_PORT_HW_PRIO_STATS_LEN;
833614d509aSAmit Cohen 	}
834614d509aSAmit Cohen 
835614d509aSAmit Cohen 	/* Per-TC Counters */
836614d509aSAmit Cohen 	for (i = 0; i < TC_MAX_QUEUE; i++) {
837614d509aSAmit Cohen 		__mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_TC_CNT, i,
838614d509aSAmit Cohen 					  data, data_index);
839614d509aSAmit Cohen 		data_index += MLXSW_SP_PORT_HW_TC_STATS_LEN;
840614d509aSAmit Cohen 	}
841614d509aSAmit Cohen 
842614d509aSAmit Cohen 	/* PTP counters */
843614d509aSAmit Cohen 	mlxsw_sp_port->mlxsw_sp->ptp_ops->get_stats(mlxsw_sp_port,
844614d509aSAmit Cohen 						    data, data_index);
845614d509aSAmit Cohen 	data_index += mlxsw_sp_port->mlxsw_sp->ptp_ops->get_stats_count();
84669f6d4eeSAmit Cohen 
84769f6d4eeSAmit Cohen 	/* Transceiver counters */
84869f6d4eeSAmit Cohen 	__mlxsw_sp_port_get_env_stats(dev, data, data_index, mlxsw_sp_port_transceiver_stats,
84969f6d4eeSAmit Cohen 				      MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN);
85069f6d4eeSAmit Cohen 	data_index += MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN;
851614d509aSAmit Cohen }
852614d509aSAmit Cohen 
mlxsw_sp_port_get_sset_count(struct net_device * dev,int sset)853614d509aSAmit Cohen static int mlxsw_sp_port_get_sset_count(struct net_device *dev, int sset)
854614d509aSAmit Cohen {
855614d509aSAmit Cohen 	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
856614d509aSAmit Cohen 
857614d509aSAmit Cohen 	switch (sset) {
858614d509aSAmit Cohen 	case ETH_SS_STATS:
859614d509aSAmit Cohen 		return MLXSW_SP_PORT_ETHTOOL_STATS_LEN +
860614d509aSAmit Cohen 			mlxsw_sp_port->mlxsw_sp->ptp_ops->get_stats_count();
861614d509aSAmit Cohen 	default:
862614d509aSAmit Cohen 		return -EOPNOTSUPP;
863614d509aSAmit Cohen 	}
864614d509aSAmit Cohen }
865614d509aSAmit Cohen 
866614d509aSAmit Cohen static void
mlxsw_sp_port_get_link_supported(struct mlxsw_sp * mlxsw_sp,u32 eth_proto_cap,struct ethtool_link_ksettings * cmd)867614d509aSAmit Cohen mlxsw_sp_port_get_link_supported(struct mlxsw_sp *mlxsw_sp, u32 eth_proto_cap,
8685fc4053dSDanielle Ratson 				 struct ethtool_link_ksettings *cmd)
869614d509aSAmit Cohen {
870614d509aSAmit Cohen 	const struct mlxsw_sp_port_type_speed_ops *ops;
871614d509aSAmit Cohen 
872614d509aSAmit Cohen 	ops = mlxsw_sp->port_type_speed_ops;
873614d509aSAmit Cohen 
874614d509aSAmit Cohen 	ethtool_link_ksettings_add_link_mode(cmd, supported, Asym_Pause);
875614d509aSAmit Cohen 	ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);
876614d509aSAmit Cohen 	ethtool_link_ksettings_add_link_mode(cmd, supported, Pause);
877614d509aSAmit Cohen 
878614d509aSAmit Cohen 	ops->from_ptys_supported_port(mlxsw_sp, eth_proto_cap, cmd);
8795fc4053dSDanielle Ratson 	ops->from_ptys_link(mlxsw_sp, eth_proto_cap,
880614d509aSAmit Cohen 			    cmd->link_modes.supported);
881614d509aSAmit Cohen }
882614d509aSAmit Cohen 
883614d509aSAmit Cohen static void
mlxsw_sp_port_get_link_advertise(struct mlxsw_sp * mlxsw_sp,u32 eth_proto_admin,bool autoneg,struct ethtool_link_ksettings * cmd)884614d509aSAmit Cohen mlxsw_sp_port_get_link_advertise(struct mlxsw_sp *mlxsw_sp,
8855fc4053dSDanielle Ratson 				 u32 eth_proto_admin, bool autoneg,
886614d509aSAmit Cohen 				 struct ethtool_link_ksettings *cmd)
887614d509aSAmit Cohen {
888614d509aSAmit Cohen 	const struct mlxsw_sp_port_type_speed_ops *ops;
889614d509aSAmit Cohen 
890614d509aSAmit Cohen 	ops = mlxsw_sp->port_type_speed_ops;
891614d509aSAmit Cohen 
892614d509aSAmit Cohen 	if (!autoneg)
893614d509aSAmit Cohen 		return;
894614d509aSAmit Cohen 
895614d509aSAmit Cohen 	ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);
8965fc4053dSDanielle Ratson 	ops->from_ptys_link(mlxsw_sp, eth_proto_admin,
897614d509aSAmit Cohen 			    cmd->link_modes.advertising);
898614d509aSAmit Cohen }
899614d509aSAmit Cohen 
900614d509aSAmit Cohen static u8
mlxsw_sp_port_connector_port(enum mlxsw_reg_ptys_connector_type connector_type)901614d509aSAmit Cohen mlxsw_sp_port_connector_port(enum mlxsw_reg_ptys_connector_type connector_type)
902614d509aSAmit Cohen {
903614d509aSAmit Cohen 	switch (connector_type) {
904614d509aSAmit Cohen 	case MLXSW_REG_PTYS_CONNECTOR_TYPE_UNKNOWN_OR_NO_CONNECTOR:
905614d509aSAmit Cohen 		return PORT_OTHER;
906614d509aSAmit Cohen 	case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_NONE:
907614d509aSAmit Cohen 		return PORT_NONE;
908614d509aSAmit Cohen 	case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_TP:
909614d509aSAmit Cohen 		return PORT_TP;
910614d509aSAmit Cohen 	case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_AUI:
911614d509aSAmit Cohen 		return PORT_AUI;
912614d509aSAmit Cohen 	case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_BNC:
913614d509aSAmit Cohen 		return PORT_BNC;
914614d509aSAmit Cohen 	case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_MII:
915614d509aSAmit Cohen 		return PORT_MII;
916614d509aSAmit Cohen 	case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_FIBRE:
917614d509aSAmit Cohen 		return PORT_FIBRE;
918614d509aSAmit Cohen 	case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_DA:
919614d509aSAmit Cohen 		return PORT_DA;
920614d509aSAmit Cohen 	case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_OTHER:
921614d509aSAmit Cohen 		return PORT_OTHER;
922614d509aSAmit Cohen 	default:
923614d509aSAmit Cohen 		WARN_ON_ONCE(1);
924614d509aSAmit Cohen 		return PORT_OTHER;
925614d509aSAmit Cohen 	}
926614d509aSAmit Cohen }
927614d509aSAmit Cohen 
mlxsw_sp_port_ptys_query(struct mlxsw_sp_port * mlxsw_sp_port,u32 * p_eth_proto_cap,u32 * p_eth_proto_admin,u32 * p_eth_proto_oper,u8 * p_connector_type)928d24ca6c0SPetr Machata static int mlxsw_sp_port_ptys_query(struct mlxsw_sp_port *mlxsw_sp_port,
929d24ca6c0SPetr Machata 				    u32 *p_eth_proto_cap, u32 *p_eth_proto_admin,
930d24ca6c0SPetr Machata 				    u32 *p_eth_proto_oper, u8 *p_connector_type)
931d24ca6c0SPetr Machata {
932d24ca6c0SPetr Machata 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
933d24ca6c0SPetr Machata 	const struct mlxsw_sp_port_type_speed_ops *ops;
934d24ca6c0SPetr Machata 	char ptys_pl[MLXSW_REG_PTYS_LEN];
935d24ca6c0SPetr Machata 	int err;
936d24ca6c0SPetr Machata 
937d24ca6c0SPetr Machata 	ops = mlxsw_sp->port_type_speed_ops;
938d24ca6c0SPetr Machata 
939d24ca6c0SPetr Machata 	ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port, 0, false);
940d24ca6c0SPetr Machata 	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);
941d24ca6c0SPetr Machata 	if (err)
942d24ca6c0SPetr Machata 		return err;
943d24ca6c0SPetr Machata 
944d24ca6c0SPetr Machata 	ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, p_eth_proto_cap, p_eth_proto_admin,
945d24ca6c0SPetr Machata 				 p_eth_proto_oper);
946d24ca6c0SPetr Machata 	if (p_connector_type)
947d24ca6c0SPetr Machata 		*p_connector_type = mlxsw_reg_ptys_connector_type_get(ptys_pl);
948d24ca6c0SPetr Machata 	return 0;
949d24ca6c0SPetr Machata }
950d24ca6c0SPetr Machata 
mlxsw_sp_port_get_link_ksettings(struct net_device * dev,struct ethtool_link_ksettings * cmd)951614d509aSAmit Cohen static int mlxsw_sp_port_get_link_ksettings(struct net_device *dev,
952614d509aSAmit Cohen 					    struct ethtool_link_ksettings *cmd)
953614d509aSAmit Cohen {
954614d509aSAmit Cohen 	u32 eth_proto_cap, eth_proto_admin, eth_proto_oper;
955614d509aSAmit Cohen 	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
956614d509aSAmit Cohen 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
957614d509aSAmit Cohen 	const struct mlxsw_sp_port_type_speed_ops *ops;
958614d509aSAmit Cohen 	u8 connector_type;
959614d509aSAmit Cohen 	bool autoneg;
960614d509aSAmit Cohen 	int err;
961614d509aSAmit Cohen 
962d24ca6c0SPetr Machata 	err = mlxsw_sp_port_ptys_query(mlxsw_sp_port, &eth_proto_cap, &eth_proto_admin,
963d24ca6c0SPetr Machata 				       &eth_proto_oper, &connector_type);
964614d509aSAmit Cohen 	if (err)
965614d509aSAmit Cohen 		return err;
966d24ca6c0SPetr Machata 
967d24ca6c0SPetr Machata 	ops = mlxsw_sp->port_type_speed_ops;
968d24ca6c0SPetr Machata 	autoneg = mlxsw_sp_port->link.autoneg;
969614d509aSAmit Cohen 
9705fc4053dSDanielle Ratson 	mlxsw_sp_port_get_link_supported(mlxsw_sp, eth_proto_cap, cmd);
971614d509aSAmit Cohen 
9725fc4053dSDanielle Ratson 	mlxsw_sp_port_get_link_advertise(mlxsw_sp, eth_proto_admin, autoneg, cmd);
973614d509aSAmit Cohen 
974614d509aSAmit Cohen 	cmd->base.autoneg = autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE;
975614d509aSAmit Cohen 	cmd->base.port = mlxsw_sp_port_connector_port(connector_type);
97625a96f05SDanielle Ratson 	ops->from_ptys_link_mode(mlxsw_sp, netif_carrier_ok(dev),
977614d509aSAmit Cohen 				 eth_proto_oper, cmd);
978614d509aSAmit Cohen 
979614d509aSAmit Cohen 	return 0;
980614d509aSAmit Cohen }
981614d509aSAmit Cohen 
982614d509aSAmit Cohen static int
mlxsw_sp_port_set_link_ksettings(struct net_device * dev,const struct ethtool_link_ksettings * cmd)983614d509aSAmit Cohen mlxsw_sp_port_set_link_ksettings(struct net_device *dev,
984614d509aSAmit Cohen 				 const struct ethtool_link_ksettings *cmd)
985614d509aSAmit Cohen {
986614d509aSAmit Cohen 	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
987614d509aSAmit Cohen 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
988614d509aSAmit Cohen 	const struct mlxsw_sp_port_type_speed_ops *ops;
989614d509aSAmit Cohen 	char ptys_pl[MLXSW_REG_PTYS_LEN];
990614d509aSAmit Cohen 	u32 eth_proto_cap, eth_proto_new;
991614d509aSAmit Cohen 	bool autoneg;
992614d509aSAmit Cohen 	int err;
993614d509aSAmit Cohen 
994614d509aSAmit Cohen 	ops = mlxsw_sp->port_type_speed_ops;
995614d509aSAmit Cohen 
996614d509aSAmit Cohen 	ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port,
997614d509aSAmit Cohen 			       0, false);
998614d509aSAmit Cohen 	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);
999614d509aSAmit Cohen 	if (err)
1000614d509aSAmit Cohen 		return err;
1001614d509aSAmit Cohen 	ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, &eth_proto_cap, NULL, NULL);
1002614d509aSAmit Cohen 
1003614d509aSAmit Cohen 	autoneg = cmd->base.autoneg == AUTONEG_ENABLE;
1004614d509aSAmit Cohen 	eth_proto_new = autoneg ?
10055fc4053dSDanielle Ratson 		ops->to_ptys_advert_link(mlxsw_sp, cmd) :
1006763ece86SDanielle Ratson 		ops->to_ptys_speed_lanes(mlxsw_sp, mlxsw_sp_port->mapping.width,
1007763ece86SDanielle Ratson 					 cmd);
1008614d509aSAmit Cohen 
1009614d509aSAmit Cohen 	eth_proto_new = eth_proto_new & eth_proto_cap;
1010614d509aSAmit Cohen 	if (!eth_proto_new) {
1011763ece86SDanielle Ratson 		netdev_err(dev, "No supported speed or lanes requested\n");
1012614d509aSAmit Cohen 		return -EINVAL;
1013614d509aSAmit Cohen 	}
1014614d509aSAmit Cohen 
1015614d509aSAmit Cohen 	ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port,
1016614d509aSAmit Cohen 			       eth_proto_new, autoneg);
1017614d509aSAmit Cohen 	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);
1018614d509aSAmit Cohen 	if (err)
1019614d509aSAmit Cohen 		return err;
1020614d509aSAmit Cohen 
1021614d509aSAmit Cohen 	mlxsw_sp_port->link.autoneg = autoneg;
1022614d509aSAmit Cohen 
1023614d509aSAmit Cohen 	if (!netif_running(dev))
1024614d509aSAmit Cohen 		return 0;
1025614d509aSAmit Cohen 
1026614d509aSAmit Cohen 	mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false);
1027614d509aSAmit Cohen 	mlxsw_sp_port_admin_status_set(mlxsw_sp_port, true);
1028614d509aSAmit Cohen 
1029614d509aSAmit Cohen 	return 0;
1030614d509aSAmit Cohen }
1031614d509aSAmit Cohen 
mlxsw_sp_get_module_info(struct net_device * netdev,struct ethtool_modinfo * modinfo)1032614d509aSAmit Cohen static int mlxsw_sp_get_module_info(struct net_device *netdev,
1033614d509aSAmit Cohen 				    struct ethtool_modinfo *modinfo)
1034614d509aSAmit Cohen {
1035614d509aSAmit Cohen 	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(netdev);
1036614d509aSAmit Cohen 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1037614d509aSAmit Cohen 
10386445eef0SJiri Pirko 	return mlxsw_env_get_module_info(netdev, mlxsw_sp->core,
10396445eef0SJiri Pirko 					 mlxsw_sp_port->mapping.slot_index,
1040614d509aSAmit Cohen 					 mlxsw_sp_port->mapping.module,
1041614d509aSAmit Cohen 					 modinfo);
1042614d509aSAmit Cohen }
1043614d509aSAmit Cohen 
mlxsw_sp_get_module_eeprom(struct net_device * netdev,struct ethtool_eeprom * ee,u8 * data)1044614d509aSAmit Cohen static int mlxsw_sp_get_module_eeprom(struct net_device *netdev,
1045614d509aSAmit Cohen 				      struct ethtool_eeprom *ee, u8 *data)
1046614d509aSAmit Cohen {
1047614d509aSAmit Cohen 	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(netdev);
1048614d509aSAmit Cohen 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
10496445eef0SJiri Pirko 	u8 slot_index = mlxsw_sp_port->mapping.slot_index;
10506445eef0SJiri Pirko 	u8 module = mlxsw_sp_port->mapping.module;
1051614d509aSAmit Cohen 
10526445eef0SJiri Pirko 	return mlxsw_env_get_module_eeprom(netdev, mlxsw_sp->core, slot_index,
10536445eef0SJiri Pirko 					   module, ee, data);
1054614d509aSAmit Cohen }
1055614d509aSAmit Cohen 
1056614d509aSAmit Cohen static int
mlxsw_sp_get_module_eeprom_by_page(struct net_device * dev,const struct ethtool_module_eeprom * page,struct netlink_ext_ack * extack)10571e27b9e4SIdo Schimmel mlxsw_sp_get_module_eeprom_by_page(struct net_device *dev,
10581e27b9e4SIdo Schimmel 				   const struct ethtool_module_eeprom *page,
10591e27b9e4SIdo Schimmel 				   struct netlink_ext_ack *extack)
10601e27b9e4SIdo Schimmel {
10611e27b9e4SIdo Schimmel 	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
10621e27b9e4SIdo Schimmel 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
10636445eef0SJiri Pirko 	u8 slot_index = mlxsw_sp_port->mapping.slot_index;
10641e27b9e4SIdo Schimmel 	u8 module = mlxsw_sp_port->mapping.module;
10651e27b9e4SIdo Schimmel 
10666445eef0SJiri Pirko 	return mlxsw_env_get_module_eeprom_by_page(mlxsw_sp->core, slot_index,
10676445eef0SJiri Pirko 						   module, page, extack);
10681e27b9e4SIdo Schimmel }
10691e27b9e4SIdo Schimmel 
10701e27b9e4SIdo Schimmel static int
mlxsw_sp_get_ts_info(struct net_device * netdev,struct ethtool_ts_info * info)1071614d509aSAmit Cohen mlxsw_sp_get_ts_info(struct net_device *netdev, struct ethtool_ts_info *info)
1072614d509aSAmit Cohen {
1073614d509aSAmit Cohen 	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(netdev);
1074614d509aSAmit Cohen 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1075614d509aSAmit Cohen 
1076614d509aSAmit Cohen 	return mlxsw_sp->ptp_ops->get_ts_info(mlxsw_sp, info);
1077614d509aSAmit Cohen }
1078614d509aSAmit Cohen 
1079c1912ab0SJakub Kicinski static void
mlxsw_sp_get_eth_phy_stats(struct net_device * dev,struct ethtool_eth_phy_stats * phy_stats)1080c1912ab0SJakub Kicinski mlxsw_sp_get_eth_phy_stats(struct net_device *dev,
1081c1912ab0SJakub Kicinski 			   struct ethtool_eth_phy_stats *phy_stats)
1082c1912ab0SJakub Kicinski {
1083c1912ab0SJakub Kicinski 	char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
1084c1912ab0SJakub Kicinski 
1085c1912ab0SJakub Kicinski 	if (mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT,
1086c1912ab0SJakub Kicinski 					0, ppcnt_pl))
1087c1912ab0SJakub Kicinski 		return;
1088c1912ab0SJakub Kicinski 
1089c1912ab0SJakub Kicinski 	phy_stats->SymbolErrorDuringCarrier =
1090c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_a_symbol_error_during_carrier_get(ppcnt_pl);
1091c1912ab0SJakub Kicinski }
1092c1912ab0SJakub Kicinski 
1093c1912ab0SJakub Kicinski static void
mlxsw_sp_get_eth_mac_stats(struct net_device * dev,struct ethtool_eth_mac_stats * mac_stats)1094c1912ab0SJakub Kicinski mlxsw_sp_get_eth_mac_stats(struct net_device *dev,
1095c1912ab0SJakub Kicinski 			   struct ethtool_eth_mac_stats *mac_stats)
1096c1912ab0SJakub Kicinski {
1097c1912ab0SJakub Kicinski 	char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
1098c1912ab0SJakub Kicinski 
1099c1912ab0SJakub Kicinski 	if (mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT,
1100c1912ab0SJakub Kicinski 					0, ppcnt_pl))
1101c1912ab0SJakub Kicinski 		return;
1102c1912ab0SJakub Kicinski 
1103c1912ab0SJakub Kicinski 	mac_stats->FramesTransmittedOK =
1104c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_a_frames_transmitted_ok_get(ppcnt_pl);
1105c1912ab0SJakub Kicinski 	mac_stats->FramesReceivedOK =
1106c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_a_frames_received_ok_get(ppcnt_pl);
1107c1912ab0SJakub Kicinski 	mac_stats->FrameCheckSequenceErrors =
1108c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_a_frame_check_sequence_errors_get(ppcnt_pl);
1109c1912ab0SJakub Kicinski 	mac_stats->AlignmentErrors =
1110c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_a_alignment_errors_get(ppcnt_pl);
1111c1912ab0SJakub Kicinski 	mac_stats->OctetsTransmittedOK =
1112c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_a_octets_transmitted_ok_get(ppcnt_pl);
1113c1912ab0SJakub Kicinski 	mac_stats->OctetsReceivedOK =
1114c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_a_octets_received_ok_get(ppcnt_pl);
1115c1912ab0SJakub Kicinski 	mac_stats->MulticastFramesXmittedOK =
1116c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_a_multicast_frames_xmitted_ok_get(ppcnt_pl);
1117c1912ab0SJakub Kicinski 	mac_stats->BroadcastFramesXmittedOK =
1118c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_a_broadcast_frames_xmitted_ok_get(ppcnt_pl);
1119c1912ab0SJakub Kicinski 	mac_stats->MulticastFramesReceivedOK =
1120c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_a_multicast_frames_received_ok_get(ppcnt_pl);
1121c1912ab0SJakub Kicinski 	mac_stats->BroadcastFramesReceivedOK =
1122c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_a_broadcast_frames_received_ok_get(ppcnt_pl);
1123c1912ab0SJakub Kicinski 	mac_stats->InRangeLengthErrors =
1124c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_a_in_range_length_errors_get(ppcnt_pl);
1125c1912ab0SJakub Kicinski 	mac_stats->OutOfRangeLengthField =
1126c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_a_out_of_range_length_field_get(ppcnt_pl);
1127c1912ab0SJakub Kicinski 	mac_stats->FrameTooLongErrors =
1128c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_a_frame_too_long_errors_get(ppcnt_pl);
1129c1912ab0SJakub Kicinski }
1130c1912ab0SJakub Kicinski 
1131c1912ab0SJakub Kicinski static void
mlxsw_sp_get_eth_ctrl_stats(struct net_device * dev,struct ethtool_eth_ctrl_stats * ctrl_stats)1132c1912ab0SJakub Kicinski mlxsw_sp_get_eth_ctrl_stats(struct net_device *dev,
1133c1912ab0SJakub Kicinski 			    struct ethtool_eth_ctrl_stats *ctrl_stats)
1134c1912ab0SJakub Kicinski {
1135c1912ab0SJakub Kicinski 	char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
1136c1912ab0SJakub Kicinski 
1137c1912ab0SJakub Kicinski 	if (mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT,
1138c1912ab0SJakub Kicinski 					0, ppcnt_pl))
1139c1912ab0SJakub Kicinski 		return;
1140c1912ab0SJakub Kicinski 
1141c1912ab0SJakub Kicinski 	ctrl_stats->MACControlFramesTransmitted =
1142c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_a_mac_control_frames_transmitted_get(ppcnt_pl);
1143c1912ab0SJakub Kicinski 	ctrl_stats->MACControlFramesReceived =
1144c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_a_mac_control_frames_received_get(ppcnt_pl);
1145c1912ab0SJakub Kicinski 	ctrl_stats->UnsupportedOpcodesReceived =
1146c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_a_unsupported_opcodes_received_get(ppcnt_pl);
1147c1912ab0SJakub Kicinski }
1148c1912ab0SJakub Kicinski 
1149c1912ab0SJakub Kicinski static const struct ethtool_rmon_hist_range mlxsw_rmon_ranges[] = {
1150c1912ab0SJakub Kicinski 	{    0,    64 },
1151c1912ab0SJakub Kicinski 	{   65,   127 },
1152c1912ab0SJakub Kicinski 	{  128,   255 },
1153c1912ab0SJakub Kicinski 	{  256,   511 },
1154c1912ab0SJakub Kicinski 	{  512,  1023 },
1155c1912ab0SJakub Kicinski 	{ 1024,  1518 },
1156c1912ab0SJakub Kicinski 	{ 1519,  2047 },
1157c1912ab0SJakub Kicinski 	{ 2048,  4095 },
1158c1912ab0SJakub Kicinski 	{ 4096,  8191 },
1159c1912ab0SJakub Kicinski 	{ 8192, 10239 },
1160c1912ab0SJakub Kicinski 	{}
1161c1912ab0SJakub Kicinski };
1162c1912ab0SJakub Kicinski 
1163c1912ab0SJakub Kicinski static void
mlxsw_sp_get_rmon_stats(struct net_device * dev,struct ethtool_rmon_stats * rmon,const struct ethtool_rmon_hist_range ** ranges)1164c1912ab0SJakub Kicinski mlxsw_sp_get_rmon_stats(struct net_device *dev,
1165c1912ab0SJakub Kicinski 			struct ethtool_rmon_stats *rmon,
1166c1912ab0SJakub Kicinski 			const struct ethtool_rmon_hist_range **ranges)
1167c1912ab0SJakub Kicinski {
1168c1912ab0SJakub Kicinski 	char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
1169c1912ab0SJakub Kicinski 
1170c1912ab0SJakub Kicinski 	if (mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_RFC_2819_CNT,
1171c1912ab0SJakub Kicinski 					0, ppcnt_pl))
1172c1912ab0SJakub Kicinski 		return;
1173c1912ab0SJakub Kicinski 
1174c1912ab0SJakub Kicinski 	rmon->undersize_pkts =
1175c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_ether_stats_undersize_pkts_get(ppcnt_pl);
1176c1912ab0SJakub Kicinski 	rmon->oversize_pkts =
1177c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_ether_stats_oversize_pkts_get(ppcnt_pl);
1178c1912ab0SJakub Kicinski 	rmon->fragments =
1179c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_ether_stats_fragments_get(ppcnt_pl);
1180c1912ab0SJakub Kicinski 
1181c1912ab0SJakub Kicinski 	rmon->hist[0] = mlxsw_reg_ppcnt_ether_stats_pkts64octets_get(ppcnt_pl);
1182c1912ab0SJakub Kicinski 	rmon->hist[1] =
1183c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_ether_stats_pkts65to127octets_get(ppcnt_pl);
1184c1912ab0SJakub Kicinski 	rmon->hist[2] =
1185c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_ether_stats_pkts128to255octets_get(ppcnt_pl);
1186c1912ab0SJakub Kicinski 	rmon->hist[3] =
1187c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_ether_stats_pkts256to511octets_get(ppcnt_pl);
1188c1912ab0SJakub Kicinski 	rmon->hist[4] =
1189c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_ether_stats_pkts512to1023octets_get(ppcnt_pl);
1190c1912ab0SJakub Kicinski 	rmon->hist[5] =
1191c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_ether_stats_pkts1024to1518octets_get(ppcnt_pl);
1192c1912ab0SJakub Kicinski 	rmon->hist[6] =
1193c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_ether_stats_pkts1519to2047octets_get(ppcnt_pl);
1194c1912ab0SJakub Kicinski 	rmon->hist[7] =
1195c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_ether_stats_pkts2048to4095octets_get(ppcnt_pl);
1196c1912ab0SJakub Kicinski 	rmon->hist[8] =
1197c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_ether_stats_pkts4096to8191octets_get(ppcnt_pl);
1198c1912ab0SJakub Kicinski 	rmon->hist[9] =
1199c1912ab0SJakub Kicinski 		mlxsw_reg_ppcnt_ether_stats_pkts8192to10239octets_get(ppcnt_pl);
1200c1912ab0SJakub Kicinski 
1201c1912ab0SJakub Kicinski 	*ranges = mlxsw_rmon_ranges;
1202c1912ab0SJakub Kicinski }
1203c1912ab0SJakub Kicinski 
mlxsw_sp_reset(struct net_device * dev,u32 * flags)120449fd3b64SIdo Schimmel static int mlxsw_sp_reset(struct net_device *dev, u32 *flags)
120549fd3b64SIdo Schimmel {
120649fd3b64SIdo Schimmel 	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
120749fd3b64SIdo Schimmel 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
12086445eef0SJiri Pirko 	u8 slot_index = mlxsw_sp_port->mapping.slot_index;
120949fd3b64SIdo Schimmel 	u8 module = mlxsw_sp_port->mapping.module;
121049fd3b64SIdo Schimmel 
12116445eef0SJiri Pirko 	return mlxsw_env_reset_module(dev, mlxsw_sp->core, slot_index,
12126445eef0SJiri Pirko 				      module, flags);
121349fd3b64SIdo Schimmel }
121449fd3b64SIdo Schimmel 
12150455dc50SIdo Schimmel static int
mlxsw_sp_get_module_power_mode(struct net_device * dev,struct ethtool_module_power_mode_params * params,struct netlink_ext_ack * extack)12160455dc50SIdo Schimmel mlxsw_sp_get_module_power_mode(struct net_device *dev,
12170455dc50SIdo Schimmel 			       struct ethtool_module_power_mode_params *params,
12180455dc50SIdo Schimmel 			       struct netlink_ext_ack *extack)
12190455dc50SIdo Schimmel {
12200455dc50SIdo Schimmel 	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
12210455dc50SIdo Schimmel 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
12226445eef0SJiri Pirko 	u8 slot_index = mlxsw_sp_port->mapping.slot_index;
12230455dc50SIdo Schimmel 	u8 module = mlxsw_sp_port->mapping.module;
12240455dc50SIdo Schimmel 
12256445eef0SJiri Pirko 	return mlxsw_env_get_module_power_mode(mlxsw_sp->core, slot_index,
12266445eef0SJiri Pirko 					       module, params, extack);
12270455dc50SIdo Schimmel }
12280455dc50SIdo Schimmel 
12290455dc50SIdo Schimmel static int
mlxsw_sp_set_module_power_mode(struct net_device * dev,const struct ethtool_module_power_mode_params * params,struct netlink_ext_ack * extack)12300455dc50SIdo Schimmel mlxsw_sp_set_module_power_mode(struct net_device *dev,
12310455dc50SIdo Schimmel 			       const struct ethtool_module_power_mode_params *params,
12320455dc50SIdo Schimmel 			       struct netlink_ext_ack *extack)
12330455dc50SIdo Schimmel {
12340455dc50SIdo Schimmel 	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
12350455dc50SIdo Schimmel 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
12366445eef0SJiri Pirko 	u8 slot_index = mlxsw_sp_port->mapping.slot_index;
12370455dc50SIdo Schimmel 	u8 module = mlxsw_sp_port->mapping.module;
12380455dc50SIdo Schimmel 
12396445eef0SJiri Pirko 	return mlxsw_env_set_module_power_mode(mlxsw_sp->core, slot_index,
12406445eef0SJiri Pirko 					       module, params->policy, extack);
12410455dc50SIdo Schimmel }
12420455dc50SIdo Schimmel 
1243614d509aSAmit Cohen const struct ethtool_ops mlxsw_sp_port_ethtool_ops = {
1244763ece86SDanielle Ratson 	.cap_link_lanes_supported	= true,
1245614d509aSAmit Cohen 	.get_drvinfo			= mlxsw_sp_port_get_drvinfo,
1246614d509aSAmit Cohen 	.get_link			= ethtool_op_get_link,
124760f30cd6SAmit Cohen 	.get_link_ext_state		= mlxsw_sp_port_get_link_ext_state,
1248614d509aSAmit Cohen 	.get_pauseparam			= mlxsw_sp_port_get_pauseparam,
1249614d509aSAmit Cohen 	.set_pauseparam			= mlxsw_sp_port_set_pauseparam,
1250614d509aSAmit Cohen 	.get_strings			= mlxsw_sp_port_get_strings,
1251614d509aSAmit Cohen 	.set_phys_id			= mlxsw_sp_port_set_phys_id,
1252614d509aSAmit Cohen 	.get_ethtool_stats		= mlxsw_sp_port_get_stats,
1253614d509aSAmit Cohen 	.get_sset_count			= mlxsw_sp_port_get_sset_count,
1254614d509aSAmit Cohen 	.get_link_ksettings		= mlxsw_sp_port_get_link_ksettings,
1255614d509aSAmit Cohen 	.set_link_ksettings		= mlxsw_sp_port_set_link_ksettings,
1256614d509aSAmit Cohen 	.get_module_info		= mlxsw_sp_get_module_info,
1257614d509aSAmit Cohen 	.get_module_eeprom		= mlxsw_sp_get_module_eeprom,
12581e27b9e4SIdo Schimmel 	.get_module_eeprom_by_page	= mlxsw_sp_get_module_eeprom_by_page,
1259614d509aSAmit Cohen 	.get_ts_info			= mlxsw_sp_get_ts_info,
1260c1912ab0SJakub Kicinski 	.get_eth_phy_stats		= mlxsw_sp_get_eth_phy_stats,
1261c1912ab0SJakub Kicinski 	.get_eth_mac_stats		= mlxsw_sp_get_eth_mac_stats,
1262c1912ab0SJakub Kicinski 	.get_eth_ctrl_stats		= mlxsw_sp_get_eth_ctrl_stats,
1263c1912ab0SJakub Kicinski 	.get_rmon_stats			= mlxsw_sp_get_rmon_stats,
126449fd3b64SIdo Schimmel 	.reset				= mlxsw_sp_reset,
12650455dc50SIdo Schimmel 	.get_module_power_mode		= mlxsw_sp_get_module_power_mode,
12660455dc50SIdo Schimmel 	.set_module_power_mode		= mlxsw_sp_set_module_power_mode,
1267614d509aSAmit Cohen };
12682be5c8a9SAmit Cohen 
12692be5c8a9SAmit Cohen struct mlxsw_sp1_port_link_mode {
12702be5c8a9SAmit Cohen 	enum ethtool_link_mode_bit_indices mask_ethtool;
12712be5c8a9SAmit Cohen 	u32 mask;
12722be5c8a9SAmit Cohen 	u32 speed;
12732be5c8a9SAmit Cohen };
12742be5c8a9SAmit Cohen 
12752be5c8a9SAmit Cohen static const struct mlxsw_sp1_port_link_mode mlxsw_sp1_port_link_mode[] = {
12762be5c8a9SAmit Cohen 	{
127778cf4b92SDanielle Ratson 		.mask		= MLXSW_REG_PTYS_ETH_SPEED_100BASE_T,
127878cf4b92SDanielle Ratson 		.mask_ethtool	= ETHTOOL_LINK_MODE_100baseT_Full_BIT,
127978cf4b92SDanielle Ratson 		.speed		= SPEED_100,
128078cf4b92SDanielle Ratson 	},
128178cf4b92SDanielle Ratson 	{
12822be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_ETH_SPEED_SGMII |
12832be5c8a9SAmit Cohen 				  MLXSW_REG_PTYS_ETH_SPEED_1000BASE_KX,
12842be5c8a9SAmit Cohen 		.mask_ethtool	= ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
12852be5c8a9SAmit Cohen 		.speed		= SPEED_1000,
12862be5c8a9SAmit Cohen 	},
12872be5c8a9SAmit Cohen 	{
128878cf4b92SDanielle Ratson 		.mask		= MLXSW_REG_PTYS_ETH_SPEED_1000BASE_T,
128978cf4b92SDanielle Ratson 		.mask_ethtool   = ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
129078cf4b92SDanielle Ratson 		.speed          = SPEED_1000,
129178cf4b92SDanielle Ratson 	},
129278cf4b92SDanielle Ratson 	{
12932be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CX4 |
12942be5c8a9SAmit Cohen 				  MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4,
12952be5c8a9SAmit Cohen 		.mask_ethtool	= ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
12962be5c8a9SAmit Cohen 		.speed		= SPEED_10000,
12972be5c8a9SAmit Cohen 	},
12982be5c8a9SAmit Cohen 	{
12992be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR |
13002be5c8a9SAmit Cohen 				  MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR |
13012be5c8a9SAmit Cohen 				  MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR |
13022be5c8a9SAmit Cohen 				  MLXSW_REG_PTYS_ETH_SPEED_10GBASE_ER_LR,
13032be5c8a9SAmit Cohen 		.mask_ethtool	= ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
13042be5c8a9SAmit Cohen 		.speed		= SPEED_10000,
13052be5c8a9SAmit Cohen 	},
13062be5c8a9SAmit Cohen 	{
13072be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4,
13082be5c8a9SAmit Cohen 		.mask_ethtool	= ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
13092be5c8a9SAmit Cohen 		.speed		= SPEED_40000,
13102be5c8a9SAmit Cohen 	},
13112be5c8a9SAmit Cohen 	{
13122be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4,
13132be5c8a9SAmit Cohen 		.mask_ethtool	= ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
13142be5c8a9SAmit Cohen 		.speed		= SPEED_40000,
13152be5c8a9SAmit Cohen 	},
13162be5c8a9SAmit Cohen 	{
13172be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4,
13182be5c8a9SAmit Cohen 		.mask_ethtool	= ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
13192be5c8a9SAmit Cohen 		.speed		= SPEED_40000,
13202be5c8a9SAmit Cohen 	},
13212be5c8a9SAmit Cohen 	{
13222be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_ETH_SPEED_40GBASE_LR4_ER4,
13232be5c8a9SAmit Cohen 		.mask_ethtool	= ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
13242be5c8a9SAmit Cohen 		.speed		= SPEED_40000,
13252be5c8a9SAmit Cohen 	},
13262be5c8a9SAmit Cohen 	{
13272be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_ETH_SPEED_25GBASE_CR,
13282be5c8a9SAmit Cohen 		.mask_ethtool	= ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
13292be5c8a9SAmit Cohen 		.speed		= SPEED_25000,
13302be5c8a9SAmit Cohen 	},
13312be5c8a9SAmit Cohen 	{
13322be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_ETH_SPEED_25GBASE_KR,
13332be5c8a9SAmit Cohen 		.mask_ethtool	= ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
13342be5c8a9SAmit Cohen 		.speed		= SPEED_25000,
13352be5c8a9SAmit Cohen 	},
13362be5c8a9SAmit Cohen 	{
13372be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_ETH_SPEED_25GBASE_SR,
13382be5c8a9SAmit Cohen 		.mask_ethtool	= ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
13392be5c8a9SAmit Cohen 		.speed		= SPEED_25000,
13402be5c8a9SAmit Cohen 	},
13412be5c8a9SAmit Cohen 	{
13422be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_ETH_SPEED_50GBASE_CR2,
13432be5c8a9SAmit Cohen 		.mask_ethtool	= ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
13442be5c8a9SAmit Cohen 		.speed		= SPEED_50000,
13452be5c8a9SAmit Cohen 	},
13462be5c8a9SAmit Cohen 	{
13472be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_ETH_SPEED_50GBASE_KR2,
13482be5c8a9SAmit Cohen 		.mask_ethtool	= ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
13492be5c8a9SAmit Cohen 		.speed		= SPEED_50000,
13502be5c8a9SAmit Cohen 	},
13512be5c8a9SAmit Cohen 	{
13522be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_ETH_SPEED_50GBASE_SR2,
13532be5c8a9SAmit Cohen 		.mask_ethtool	= ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
13542be5c8a9SAmit Cohen 		.speed		= SPEED_50000,
13552be5c8a9SAmit Cohen 	},
13562be5c8a9SAmit Cohen 	{
13572be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_ETH_SPEED_100GBASE_CR4,
13582be5c8a9SAmit Cohen 		.mask_ethtool	= ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
13592be5c8a9SAmit Cohen 		.speed		= SPEED_100000,
13602be5c8a9SAmit Cohen 	},
13612be5c8a9SAmit Cohen 	{
13622be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4,
13632be5c8a9SAmit Cohen 		.mask_ethtool	= ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
13642be5c8a9SAmit Cohen 		.speed		= SPEED_100000,
13652be5c8a9SAmit Cohen 	},
13662be5c8a9SAmit Cohen 	{
13672be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4,
13682be5c8a9SAmit Cohen 		.mask_ethtool	= ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
13692be5c8a9SAmit Cohen 		.speed		= SPEED_100000,
13702be5c8a9SAmit Cohen 	},
1371ae9b24ddSDanielle Ratson 	{
1372ae9b24ddSDanielle Ratson 		.mask		= MLXSW_REG_PTYS_ETH_SPEED_100GBASE_LR4_ER4,
1373ae9b24ddSDanielle Ratson 		.mask_ethtool	= ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
1374ae9b24ddSDanielle Ratson 		.speed		= SPEED_100000,
1375ae9b24ddSDanielle Ratson 	},
13762be5c8a9SAmit Cohen };
13772be5c8a9SAmit Cohen 
13782be5c8a9SAmit Cohen #define MLXSW_SP1_PORT_LINK_MODE_LEN ARRAY_SIZE(mlxsw_sp1_port_link_mode)
13792be5c8a9SAmit Cohen 
13802be5c8a9SAmit Cohen static void
mlxsw_sp1_from_ptys_supported_port(struct mlxsw_sp * mlxsw_sp,u32 ptys_eth_proto,struct ethtool_link_ksettings * cmd)13812be5c8a9SAmit Cohen mlxsw_sp1_from_ptys_supported_port(struct mlxsw_sp *mlxsw_sp,
13822be5c8a9SAmit Cohen 				   u32 ptys_eth_proto,
13832be5c8a9SAmit Cohen 				   struct ethtool_link_ksettings *cmd)
13842be5c8a9SAmit Cohen {
13852be5c8a9SAmit Cohen 	if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR |
13862be5c8a9SAmit Cohen 			      MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR |
13872be5c8a9SAmit Cohen 			      MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4 |
13882be5c8a9SAmit Cohen 			      MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4 |
13892be5c8a9SAmit Cohen 			      MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4 |
13902be5c8a9SAmit Cohen 			      MLXSW_REG_PTYS_ETH_SPEED_SGMII))
13912be5c8a9SAmit Cohen 		ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
13922be5c8a9SAmit Cohen 
13932be5c8a9SAmit Cohen 	if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR |
13942be5c8a9SAmit Cohen 			      MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4 |
13952be5c8a9SAmit Cohen 			      MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4 |
13962be5c8a9SAmit Cohen 			      MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4 |
13972be5c8a9SAmit Cohen 			      MLXSW_REG_PTYS_ETH_SPEED_1000BASE_KX))
13982be5c8a9SAmit Cohen 		ethtool_link_ksettings_add_link_mode(cmd, supported, Backplane);
13992be5c8a9SAmit Cohen }
14002be5c8a9SAmit Cohen 
14012be5c8a9SAmit Cohen static void
mlxsw_sp1_from_ptys_link(struct mlxsw_sp * mlxsw_sp,u32 ptys_eth_proto,unsigned long * mode)14022be5c8a9SAmit Cohen mlxsw_sp1_from_ptys_link(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto,
14035fc4053dSDanielle Ratson 			 unsigned long *mode)
14042be5c8a9SAmit Cohen {
14052be5c8a9SAmit Cohen 	int i;
14062be5c8a9SAmit Cohen 
14072be5c8a9SAmit Cohen 	for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
14082be5c8a9SAmit Cohen 		if (ptys_eth_proto & mlxsw_sp1_port_link_mode[i].mask)
14092be5c8a9SAmit Cohen 			__set_bit(mlxsw_sp1_port_link_mode[i].mask_ethtool,
14102be5c8a9SAmit Cohen 				  mode);
14112be5c8a9SAmit Cohen 	}
14122be5c8a9SAmit Cohen }
14132be5c8a9SAmit Cohen 
14142be5c8a9SAmit Cohen static u32
mlxsw_sp1_from_ptys_speed(struct mlxsw_sp * mlxsw_sp,u32 ptys_eth_proto)14152be5c8a9SAmit Cohen mlxsw_sp1_from_ptys_speed(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto)
14162be5c8a9SAmit Cohen {
14172be5c8a9SAmit Cohen 	int i;
14182be5c8a9SAmit Cohen 
14192be5c8a9SAmit Cohen 	for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
14202be5c8a9SAmit Cohen 		if (ptys_eth_proto & mlxsw_sp1_port_link_mode[i].mask)
14212be5c8a9SAmit Cohen 			return mlxsw_sp1_port_link_mode[i].speed;
14222be5c8a9SAmit Cohen 	}
14232be5c8a9SAmit Cohen 
14242be5c8a9SAmit Cohen 	return SPEED_UNKNOWN;
14252be5c8a9SAmit Cohen }
14262be5c8a9SAmit Cohen 
14272be5c8a9SAmit Cohen static void
mlxsw_sp1_from_ptys_link_mode(struct mlxsw_sp * mlxsw_sp,bool carrier_ok,u32 ptys_eth_proto,struct ethtool_link_ksettings * cmd)142825a96f05SDanielle Ratson mlxsw_sp1_from_ptys_link_mode(struct mlxsw_sp *mlxsw_sp, bool carrier_ok,
14292be5c8a9SAmit Cohen 			      u32 ptys_eth_proto,
14302be5c8a9SAmit Cohen 			      struct ethtool_link_ksettings *cmd)
14312be5c8a9SAmit Cohen {
1432a975d7d8SDanielle Ratson 	struct mlxsw_sp1_port_link_mode link;
143325a96f05SDanielle Ratson 	int i;
143425a96f05SDanielle Ratson 
1435a975d7d8SDanielle Ratson 	cmd->base.speed = SPEED_UNKNOWN;
1436a975d7d8SDanielle Ratson 	cmd->base.duplex = DUPLEX_UNKNOWN;
1437a975d7d8SDanielle Ratson 	cmd->lanes = 0;
14382be5c8a9SAmit Cohen 
14392be5c8a9SAmit Cohen 	if (!carrier_ok)
14402be5c8a9SAmit Cohen 		return;
14412be5c8a9SAmit Cohen 
144225a96f05SDanielle Ratson 	for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
1443a975d7d8SDanielle Ratson 		if (ptys_eth_proto & mlxsw_sp1_port_link_mode[i].mask) {
1444a975d7d8SDanielle Ratson 			link = mlxsw_sp1_port_link_mode[i];
1445a975d7d8SDanielle Ratson 			ethtool_params_from_link_mode(cmd,
1446a975d7d8SDanielle Ratson 						      link.mask_ethtool);
1447a975d7d8SDanielle Ratson 		}
144825a96f05SDanielle Ratson 	}
14492be5c8a9SAmit Cohen }
14502be5c8a9SAmit Cohen 
mlxsw_sp1_ptys_max_speed(struct mlxsw_sp_port * mlxsw_sp_port,u32 * p_max_speed)145160fbc521SPetr Machata static int mlxsw_sp1_ptys_max_speed(struct mlxsw_sp_port *mlxsw_sp_port, u32 *p_max_speed)
145260fbc521SPetr Machata {
145360fbc521SPetr Machata 	u32 eth_proto_cap;
145460fbc521SPetr Machata 	u32 max_speed = 0;
145560fbc521SPetr Machata 	int err;
145660fbc521SPetr Machata 	int i;
145760fbc521SPetr Machata 
145860fbc521SPetr Machata 	err = mlxsw_sp_port_ptys_query(mlxsw_sp_port, &eth_proto_cap, NULL, NULL, NULL);
145960fbc521SPetr Machata 	if (err)
146060fbc521SPetr Machata 		return err;
146160fbc521SPetr Machata 
146260fbc521SPetr Machata 	for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
146360fbc521SPetr Machata 		if ((eth_proto_cap & mlxsw_sp1_port_link_mode[i].mask) &&
146460fbc521SPetr Machata 		    mlxsw_sp1_port_link_mode[i].speed > max_speed)
146560fbc521SPetr Machata 			max_speed = mlxsw_sp1_port_link_mode[i].speed;
146660fbc521SPetr Machata 	}
146760fbc521SPetr Machata 
146860fbc521SPetr Machata 	*p_max_speed = max_speed;
146960fbc521SPetr Machata 	return 0;
147060fbc521SPetr Machata }
147160fbc521SPetr Machata 
14722be5c8a9SAmit Cohen static u32
mlxsw_sp1_to_ptys_advert_link(struct mlxsw_sp * mlxsw_sp,const struct ethtool_link_ksettings * cmd)14735fc4053dSDanielle Ratson mlxsw_sp1_to_ptys_advert_link(struct mlxsw_sp *mlxsw_sp,
14742be5c8a9SAmit Cohen 			      const struct ethtool_link_ksettings *cmd)
14752be5c8a9SAmit Cohen {
14762be5c8a9SAmit Cohen 	u32 ptys_proto = 0;
14772be5c8a9SAmit Cohen 	int i;
14782be5c8a9SAmit Cohen 
14792be5c8a9SAmit Cohen 	for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
14802be5c8a9SAmit Cohen 		if (test_bit(mlxsw_sp1_port_link_mode[i].mask_ethtool,
14812be5c8a9SAmit Cohen 			     cmd->link_modes.advertising))
14822be5c8a9SAmit Cohen 			ptys_proto |= mlxsw_sp1_port_link_mode[i].mask;
14832be5c8a9SAmit Cohen 	}
14842be5c8a9SAmit Cohen 	return ptys_proto;
14852be5c8a9SAmit Cohen }
14862be5c8a9SAmit Cohen 
mlxsw_sp1_to_ptys_speed_lanes(struct mlxsw_sp * mlxsw_sp,u8 width,const struct ethtool_link_ksettings * cmd)1487763ece86SDanielle Ratson static u32 mlxsw_sp1_to_ptys_speed_lanes(struct mlxsw_sp *mlxsw_sp, u8 width,
1488763ece86SDanielle Ratson 					 const struct ethtool_link_ksettings *cmd)
14892be5c8a9SAmit Cohen {
14902be5c8a9SAmit Cohen 	u32 ptys_proto = 0;
14912be5c8a9SAmit Cohen 	int i;
14922be5c8a9SAmit Cohen 
1493763ece86SDanielle Ratson 	if (cmd->lanes > width)
1494763ece86SDanielle Ratson 		return ptys_proto;
1495763ece86SDanielle Ratson 
14962be5c8a9SAmit Cohen 	for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
1497763ece86SDanielle Ratson 		if (cmd->base.speed == mlxsw_sp1_port_link_mode[i].speed)
14982be5c8a9SAmit Cohen 			ptys_proto |= mlxsw_sp1_port_link_mode[i].mask;
14992be5c8a9SAmit Cohen 	}
15002be5c8a9SAmit Cohen 	return ptys_proto;
15012be5c8a9SAmit Cohen }
15022be5c8a9SAmit Cohen 
15032be5c8a9SAmit Cohen static void
mlxsw_sp1_reg_ptys_eth_pack(struct mlxsw_sp * mlxsw_sp,char * payload,u16 local_port,u32 proto_admin,bool autoneg)15042be5c8a9SAmit Cohen mlxsw_sp1_reg_ptys_eth_pack(struct mlxsw_sp *mlxsw_sp, char *payload,
1505c934757dSAmit Cohen 			    u16 local_port, u32 proto_admin, bool autoneg)
15062be5c8a9SAmit Cohen {
15072be5c8a9SAmit Cohen 	mlxsw_reg_ptys_eth_pack(payload, local_port, proto_admin, autoneg);
15082be5c8a9SAmit Cohen }
15092be5c8a9SAmit Cohen 
15102be5c8a9SAmit Cohen static void
mlxsw_sp1_reg_ptys_eth_unpack(struct mlxsw_sp * mlxsw_sp,char * payload,u32 * p_eth_proto_cap,u32 * p_eth_proto_admin,u32 * p_eth_proto_oper)15112be5c8a9SAmit Cohen mlxsw_sp1_reg_ptys_eth_unpack(struct mlxsw_sp *mlxsw_sp, char *payload,
15122be5c8a9SAmit Cohen 			      u32 *p_eth_proto_cap, u32 *p_eth_proto_admin,
15132be5c8a9SAmit Cohen 			      u32 *p_eth_proto_oper)
15142be5c8a9SAmit Cohen {
15152be5c8a9SAmit Cohen 	mlxsw_reg_ptys_eth_unpack(payload, p_eth_proto_cap, p_eth_proto_admin,
15162be5c8a9SAmit Cohen 				  p_eth_proto_oper);
15172be5c8a9SAmit Cohen }
15182be5c8a9SAmit Cohen 
mlxsw_sp1_ptys_proto_cap_masked_get(u32 eth_proto_cap)15191601559bSAmit Cohen static u32 mlxsw_sp1_ptys_proto_cap_masked_get(u32 eth_proto_cap)
15201601559bSAmit Cohen {
15211601559bSAmit Cohen 	u32 ptys_proto_cap_masked = 0;
15221601559bSAmit Cohen 	int i;
15231601559bSAmit Cohen 
15241601559bSAmit Cohen 	for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
15251601559bSAmit Cohen 		if (mlxsw_sp1_port_link_mode[i].mask & eth_proto_cap)
15261601559bSAmit Cohen 			ptys_proto_cap_masked |=
15271601559bSAmit Cohen 				mlxsw_sp1_port_link_mode[i].mask;
15281601559bSAmit Cohen 	}
15291601559bSAmit Cohen 
15301601559bSAmit Cohen 	return ptys_proto_cap_masked;
15311601559bSAmit Cohen }
15321601559bSAmit Cohen 
15332be5c8a9SAmit Cohen const struct mlxsw_sp_port_type_speed_ops mlxsw_sp1_port_type_speed_ops = {
15342be5c8a9SAmit Cohen 	.from_ptys_supported_port	= mlxsw_sp1_from_ptys_supported_port,
15352be5c8a9SAmit Cohen 	.from_ptys_link			= mlxsw_sp1_from_ptys_link,
15362be5c8a9SAmit Cohen 	.from_ptys_speed		= mlxsw_sp1_from_ptys_speed,
153725a96f05SDanielle Ratson 	.from_ptys_link_mode		= mlxsw_sp1_from_ptys_link_mode,
153860fbc521SPetr Machata 	.ptys_max_speed			= mlxsw_sp1_ptys_max_speed,
15392be5c8a9SAmit Cohen 	.to_ptys_advert_link		= mlxsw_sp1_to_ptys_advert_link,
1540763ece86SDanielle Ratson 	.to_ptys_speed_lanes		= mlxsw_sp1_to_ptys_speed_lanes,
15412be5c8a9SAmit Cohen 	.reg_ptys_eth_pack		= mlxsw_sp1_reg_ptys_eth_pack,
15422be5c8a9SAmit Cohen 	.reg_ptys_eth_unpack		= mlxsw_sp1_reg_ptys_eth_unpack,
15431601559bSAmit Cohen 	.ptys_proto_cap_masked_get	= mlxsw_sp1_ptys_proto_cap_masked_get,
15442be5c8a9SAmit Cohen };
15452be5c8a9SAmit Cohen 
15462be5c8a9SAmit Cohen static const enum ethtool_link_mode_bit_indices
15472be5c8a9SAmit Cohen mlxsw_sp2_mask_ethtool_sgmii_100m[] = {
15482be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_100baseT_Full_BIT,
15492be5c8a9SAmit Cohen };
15502be5c8a9SAmit Cohen 
15512be5c8a9SAmit Cohen #define MLXSW_SP2_MASK_ETHTOOL_SGMII_100M_LEN \
15522be5c8a9SAmit Cohen 	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_sgmii_100m)
15532be5c8a9SAmit Cohen 
15542be5c8a9SAmit Cohen static const enum ethtool_link_mode_bit_indices
15552be5c8a9SAmit Cohen mlxsw_sp2_mask_ethtool_1000base_x_sgmii[] = {
15562be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
15572be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
15582be5c8a9SAmit Cohen };
15592be5c8a9SAmit Cohen 
15602be5c8a9SAmit Cohen #define MLXSW_SP2_MASK_ETHTOOL_1000BASE_X_SGMII_LEN \
15612be5c8a9SAmit Cohen 	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_1000base_x_sgmii)
15622be5c8a9SAmit Cohen 
15632be5c8a9SAmit Cohen static const enum ethtool_link_mode_bit_indices
15642be5c8a9SAmit Cohen mlxsw_sp2_mask_ethtool_5gbase_r[] = {
15652be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
15662be5c8a9SAmit Cohen };
15672be5c8a9SAmit Cohen 
15682be5c8a9SAmit Cohen #define MLXSW_SP2_MASK_ETHTOOL_5GBASE_R_LEN \
15692be5c8a9SAmit Cohen 	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_5gbase_r)
15702be5c8a9SAmit Cohen 
15712be5c8a9SAmit Cohen static const enum ethtool_link_mode_bit_indices
15722be5c8a9SAmit Cohen mlxsw_sp2_mask_ethtool_xfi_xaui_1_10g[] = {
15732be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
15742be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
15752be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
15762be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
15772be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
15782be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
15792be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
15802be5c8a9SAmit Cohen };
15812be5c8a9SAmit Cohen 
15822be5c8a9SAmit Cohen #define MLXSW_SP2_MASK_ETHTOOL_XFI_XAUI_1_10G_LEN \
15832be5c8a9SAmit Cohen 	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_xfi_xaui_1_10g)
15842be5c8a9SAmit Cohen 
15852be5c8a9SAmit Cohen static const enum ethtool_link_mode_bit_indices
15862be5c8a9SAmit Cohen mlxsw_sp2_mask_ethtool_xlaui_4_xlppi_4_40g[] = {
15872be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
15882be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
15892be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
15902be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
15912be5c8a9SAmit Cohen };
15922be5c8a9SAmit Cohen 
15932be5c8a9SAmit Cohen #define MLXSW_SP2_MASK_ETHTOOL_XLAUI_4_XLPPI_4_40G_LEN \
15942be5c8a9SAmit Cohen 	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_xlaui_4_xlppi_4_40g)
15952be5c8a9SAmit Cohen 
15962be5c8a9SAmit Cohen static const enum ethtool_link_mode_bit_indices
15972be5c8a9SAmit Cohen mlxsw_sp2_mask_ethtool_25gaui_1_25gbase_cr_kr[] = {
15982be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
15992be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
16002be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
16012be5c8a9SAmit Cohen };
16022be5c8a9SAmit Cohen 
16032be5c8a9SAmit Cohen #define MLXSW_SP2_MASK_ETHTOOL_25GAUI_1_25GBASE_CR_KR_LEN \
16042be5c8a9SAmit Cohen 	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_25gaui_1_25gbase_cr_kr)
16052be5c8a9SAmit Cohen 
16062be5c8a9SAmit Cohen static const enum ethtool_link_mode_bit_indices
16072be5c8a9SAmit Cohen mlxsw_sp2_mask_ethtool_50gaui_2_laui_2_50gbase_cr2_kr2[] = {
16082be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
16092be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
16102be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
16112be5c8a9SAmit Cohen };
16122be5c8a9SAmit Cohen 
16132be5c8a9SAmit Cohen #define MLXSW_SP2_MASK_ETHTOOL_50GAUI_2_LAUI_2_50GBASE_CR2_KR2_LEN \
16142be5c8a9SAmit Cohen 	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_50gaui_2_laui_2_50gbase_cr2_kr2)
16152be5c8a9SAmit Cohen 
16162be5c8a9SAmit Cohen static const enum ethtool_link_mode_bit_indices
16172be5c8a9SAmit Cohen mlxsw_sp2_mask_ethtool_50gaui_1_laui_1_50gbase_cr_kr[] = {
16182be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
16192be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
16202be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
16212be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
16222be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_50000baseDR_Full_BIT,
16232be5c8a9SAmit Cohen };
16242be5c8a9SAmit Cohen 
16252be5c8a9SAmit Cohen #define MLXSW_SP2_MASK_ETHTOOL_50GAUI_1_LAUI_1_50GBASE_CR_KR_LEN \
16262be5c8a9SAmit Cohen 	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_50gaui_1_laui_1_50gbase_cr_kr)
16272be5c8a9SAmit Cohen 
16282be5c8a9SAmit Cohen static const enum ethtool_link_mode_bit_indices
16292be5c8a9SAmit Cohen mlxsw_sp2_mask_ethtool_caui_4_100gbase_cr4_kr4[] = {
16302be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
16312be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
16322be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
16332be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
16342be5c8a9SAmit Cohen };
16352be5c8a9SAmit Cohen 
16362be5c8a9SAmit Cohen #define MLXSW_SP2_MASK_ETHTOOL_CAUI_4_100GBASE_CR4_KR4_LEN \
16372be5c8a9SAmit Cohen 	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_caui_4_100gbase_cr4_kr4)
16382be5c8a9SAmit Cohen 
16392be5c8a9SAmit Cohen static const enum ethtool_link_mode_bit_indices
16402be5c8a9SAmit Cohen mlxsw_sp2_mask_ethtool_100gaui_2_100gbase_cr2_kr2[] = {
16412be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT,
16422be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT,
16432be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT,
16442be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
16452be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT,
16462be5c8a9SAmit Cohen };
16472be5c8a9SAmit Cohen 
16482be5c8a9SAmit Cohen #define MLXSW_SP2_MASK_ETHTOOL_100GAUI_2_100GBASE_CR2_KR2_LEN \
16492be5c8a9SAmit Cohen 	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_100gaui_2_100gbase_cr2_kr2)
16502be5c8a9SAmit Cohen 
16512be5c8a9SAmit Cohen static const enum ethtool_link_mode_bit_indices
16522be5c8a9SAmit Cohen mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4[] = {
16532be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT,
16542be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT,
16552be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT,
16562be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT,
16572be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT,
16582be5c8a9SAmit Cohen };
16592be5c8a9SAmit Cohen 
16602be5c8a9SAmit Cohen #define MLXSW_SP2_MASK_ETHTOOL_200GAUI_4_200GBASE_CR4_KR4_LEN \
16612be5c8a9SAmit Cohen 	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4)
16622be5c8a9SAmit Cohen 
16632be5c8a9SAmit Cohen static const enum ethtool_link_mode_bit_indices
16642be5c8a9SAmit Cohen mlxsw_sp2_mask_ethtool_400gaui_8[] = {
16652be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT,
16662be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT,
16672be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT,
16682be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT,
16692be5c8a9SAmit Cohen 	ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT,
16702be5c8a9SAmit Cohen };
16712be5c8a9SAmit Cohen 
16722be5c8a9SAmit Cohen #define MLXSW_SP2_MASK_ETHTOOL_400GAUI_8_LEN \
16732be5c8a9SAmit Cohen 	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_400gaui_8)
16742be5c8a9SAmit Cohen 
1675*cceef209SAmit Cohen static const enum ethtool_link_mode_bit_indices
1676*cceef209SAmit Cohen mlxsw_sp2_mask_ethtool_800gaui_8[] = {
1677*cceef209SAmit Cohen 	ETHTOOL_LINK_MODE_800000baseCR8_Full_BIT,
1678*cceef209SAmit Cohen 	ETHTOOL_LINK_MODE_800000baseKR8_Full_BIT,
1679*cceef209SAmit Cohen 	ETHTOOL_LINK_MODE_800000baseDR8_Full_BIT,
1680*cceef209SAmit Cohen 	ETHTOOL_LINK_MODE_800000baseDR8_2_Full_BIT,
1681*cceef209SAmit Cohen 	ETHTOOL_LINK_MODE_800000baseSR8_Full_BIT,
1682*cceef209SAmit Cohen 	ETHTOOL_LINK_MODE_800000baseVR8_Full_BIT,
1683*cceef209SAmit Cohen };
1684*cceef209SAmit Cohen 
1685*cceef209SAmit Cohen #define MLXSW_SP2_MASK_ETHTOOL_800GAUI_8_LEN \
1686*cceef209SAmit Cohen 	ARRAY_SIZE(mlxsw_sp2_mask_ethtool_800gaui_8)
1687*cceef209SAmit Cohen 
16882be5c8a9SAmit Cohen #define MLXSW_SP_PORT_MASK_WIDTH_1X	BIT(0)
16892be5c8a9SAmit Cohen #define MLXSW_SP_PORT_MASK_WIDTH_2X	BIT(1)
16902be5c8a9SAmit Cohen #define MLXSW_SP_PORT_MASK_WIDTH_4X	BIT(2)
16912be5c8a9SAmit Cohen #define MLXSW_SP_PORT_MASK_WIDTH_8X	BIT(3)
16922be5c8a9SAmit Cohen 
mlxsw_sp_port_mask_width_get(u8 width)16932be5c8a9SAmit Cohen static u8 mlxsw_sp_port_mask_width_get(u8 width)
16942be5c8a9SAmit Cohen {
16952be5c8a9SAmit Cohen 	switch (width) {
16962be5c8a9SAmit Cohen 	case 1:
16972be5c8a9SAmit Cohen 		return MLXSW_SP_PORT_MASK_WIDTH_1X;
16982be5c8a9SAmit Cohen 	case 2:
16992be5c8a9SAmit Cohen 		return MLXSW_SP_PORT_MASK_WIDTH_2X;
17002be5c8a9SAmit Cohen 	case 4:
17012be5c8a9SAmit Cohen 		return MLXSW_SP_PORT_MASK_WIDTH_4X;
17022be5c8a9SAmit Cohen 	case 8:
17032be5c8a9SAmit Cohen 		return MLXSW_SP_PORT_MASK_WIDTH_8X;
17042be5c8a9SAmit Cohen 	default:
17052be5c8a9SAmit Cohen 		WARN_ON_ONCE(1);
17062be5c8a9SAmit Cohen 		return 0;
17072be5c8a9SAmit Cohen 	}
17082be5c8a9SAmit Cohen }
17092be5c8a9SAmit Cohen 
17102be5c8a9SAmit Cohen struct mlxsw_sp2_port_link_mode {
17112be5c8a9SAmit Cohen 	const enum ethtool_link_mode_bit_indices *mask_ethtool;
17122be5c8a9SAmit Cohen 	int m_ethtool_len;
17132be5c8a9SAmit Cohen 	u32 mask;
17142be5c8a9SAmit Cohen 	u32 speed;
1715763ece86SDanielle Ratson 	u32 width;
1716763ece86SDanielle Ratson 	u8 mask_sup_width;
17172be5c8a9SAmit Cohen };
17182be5c8a9SAmit Cohen 
17192be5c8a9SAmit Cohen static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = {
17202be5c8a9SAmit Cohen 	{
17212be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_SGMII_100M,
17222be5c8a9SAmit Cohen 		.mask_ethtool	= mlxsw_sp2_mask_ethtool_sgmii_100m,
17232be5c8a9SAmit Cohen 		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_SGMII_100M_LEN,
1724763ece86SDanielle Ratson 		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_1X |
17252be5c8a9SAmit Cohen 				  MLXSW_SP_PORT_MASK_WIDTH_2X |
17262be5c8a9SAmit Cohen 				  MLXSW_SP_PORT_MASK_WIDTH_4X |
17272be5c8a9SAmit Cohen 				  MLXSW_SP_PORT_MASK_WIDTH_8X,
17282be5c8a9SAmit Cohen 		.speed		= SPEED_100,
1729763ece86SDanielle Ratson 		.width		= 1,
17302be5c8a9SAmit Cohen 	},
17312be5c8a9SAmit Cohen 	{
17322be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_1000BASE_X_SGMII,
17332be5c8a9SAmit Cohen 		.mask_ethtool	= mlxsw_sp2_mask_ethtool_1000base_x_sgmii,
17342be5c8a9SAmit Cohen 		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_1000BASE_X_SGMII_LEN,
1735763ece86SDanielle Ratson 		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_1X |
17362be5c8a9SAmit Cohen 				  MLXSW_SP_PORT_MASK_WIDTH_2X |
17372be5c8a9SAmit Cohen 				  MLXSW_SP_PORT_MASK_WIDTH_4X |
17382be5c8a9SAmit Cohen 				  MLXSW_SP_PORT_MASK_WIDTH_8X,
17392be5c8a9SAmit Cohen 		.speed		= SPEED_1000,
1740763ece86SDanielle Ratson 		.width		= 1,
17412be5c8a9SAmit Cohen 	},
17422be5c8a9SAmit Cohen 	{
17432be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_5GBASE_R,
17442be5c8a9SAmit Cohen 		.mask_ethtool	= mlxsw_sp2_mask_ethtool_5gbase_r,
17452be5c8a9SAmit Cohen 		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_5GBASE_R_LEN,
1746763ece86SDanielle Ratson 		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_1X |
17472be5c8a9SAmit Cohen 				  MLXSW_SP_PORT_MASK_WIDTH_2X |
17482be5c8a9SAmit Cohen 				  MLXSW_SP_PORT_MASK_WIDTH_4X |
17492be5c8a9SAmit Cohen 				  MLXSW_SP_PORT_MASK_WIDTH_8X,
17502be5c8a9SAmit Cohen 		.speed		= SPEED_5000,
1751763ece86SDanielle Ratson 		.width		= 1,
17522be5c8a9SAmit Cohen 	},
17532be5c8a9SAmit Cohen 	{
17542be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_XFI_XAUI_1_10G,
17552be5c8a9SAmit Cohen 		.mask_ethtool	= mlxsw_sp2_mask_ethtool_xfi_xaui_1_10g,
17562be5c8a9SAmit Cohen 		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_XFI_XAUI_1_10G_LEN,
1757763ece86SDanielle Ratson 		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_1X |
17582be5c8a9SAmit Cohen 				  MLXSW_SP_PORT_MASK_WIDTH_2X |
17592be5c8a9SAmit Cohen 				  MLXSW_SP_PORT_MASK_WIDTH_4X |
17602be5c8a9SAmit Cohen 				  MLXSW_SP_PORT_MASK_WIDTH_8X,
17612be5c8a9SAmit Cohen 		.speed		= SPEED_10000,
1762763ece86SDanielle Ratson 		.width		= 1,
17632be5c8a9SAmit Cohen 	},
17642be5c8a9SAmit Cohen 	{
17652be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_XLAUI_4_XLPPI_4_40G,
17662be5c8a9SAmit Cohen 		.mask_ethtool	= mlxsw_sp2_mask_ethtool_xlaui_4_xlppi_4_40g,
17672be5c8a9SAmit Cohen 		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_XLAUI_4_XLPPI_4_40G_LEN,
1768763ece86SDanielle Ratson 		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_4X |
17692be5c8a9SAmit Cohen 				  MLXSW_SP_PORT_MASK_WIDTH_8X,
17702be5c8a9SAmit Cohen 		.speed		= SPEED_40000,
1771763ece86SDanielle Ratson 		.width		= 4,
17722be5c8a9SAmit Cohen 	},
17732be5c8a9SAmit Cohen 	{
17742be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_25GAUI_1_25GBASE_CR_KR,
17752be5c8a9SAmit Cohen 		.mask_ethtool	= mlxsw_sp2_mask_ethtool_25gaui_1_25gbase_cr_kr,
17762be5c8a9SAmit Cohen 		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_25GAUI_1_25GBASE_CR_KR_LEN,
1777763ece86SDanielle Ratson 		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_1X |
17782be5c8a9SAmit Cohen 				  MLXSW_SP_PORT_MASK_WIDTH_2X |
17792be5c8a9SAmit Cohen 				  MLXSW_SP_PORT_MASK_WIDTH_4X |
17802be5c8a9SAmit Cohen 				  MLXSW_SP_PORT_MASK_WIDTH_8X,
17812be5c8a9SAmit Cohen 		.speed		= SPEED_25000,
1782763ece86SDanielle Ratson 		.width		= 1,
17832be5c8a9SAmit Cohen 	},
17842be5c8a9SAmit Cohen 	{
17852be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_50GAUI_2_LAUI_2_50GBASE_CR2_KR2,
17862be5c8a9SAmit Cohen 		.mask_ethtool	= mlxsw_sp2_mask_ethtool_50gaui_2_laui_2_50gbase_cr2_kr2,
17872be5c8a9SAmit Cohen 		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_50GAUI_2_LAUI_2_50GBASE_CR2_KR2_LEN,
1788763ece86SDanielle Ratson 		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_2X |
17892be5c8a9SAmit Cohen 				  MLXSW_SP_PORT_MASK_WIDTH_4X |
17902be5c8a9SAmit Cohen 				  MLXSW_SP_PORT_MASK_WIDTH_8X,
17912be5c8a9SAmit Cohen 		.speed		= SPEED_50000,
1792763ece86SDanielle Ratson 		.width		= 2,
17932be5c8a9SAmit Cohen 	},
17942be5c8a9SAmit Cohen 	{
17952be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_50GAUI_1_LAUI_1_50GBASE_CR_KR,
17962be5c8a9SAmit Cohen 		.mask_ethtool	= mlxsw_sp2_mask_ethtool_50gaui_1_laui_1_50gbase_cr_kr,
17972be5c8a9SAmit Cohen 		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_50GAUI_1_LAUI_1_50GBASE_CR_KR_LEN,
1798763ece86SDanielle Ratson 		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_1X,
17992be5c8a9SAmit Cohen 		.speed		= SPEED_50000,
1800763ece86SDanielle Ratson 		.width		= 1,
18012be5c8a9SAmit Cohen 	},
18022be5c8a9SAmit Cohen 	{
18032be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_CAUI_4_100GBASE_CR4_KR4,
18042be5c8a9SAmit Cohen 		.mask_ethtool	= mlxsw_sp2_mask_ethtool_caui_4_100gbase_cr4_kr4,
18052be5c8a9SAmit Cohen 		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_CAUI_4_100GBASE_CR4_KR4_LEN,
1806763ece86SDanielle Ratson 		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_4X |
18072be5c8a9SAmit Cohen 				  MLXSW_SP_PORT_MASK_WIDTH_8X,
18082be5c8a9SAmit Cohen 		.speed		= SPEED_100000,
1809763ece86SDanielle Ratson 		.width		= 4,
18102be5c8a9SAmit Cohen 	},
18112be5c8a9SAmit Cohen 	{
18122be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_100GAUI_2_100GBASE_CR2_KR2,
18132be5c8a9SAmit Cohen 		.mask_ethtool	= mlxsw_sp2_mask_ethtool_100gaui_2_100gbase_cr2_kr2,
18142be5c8a9SAmit Cohen 		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_100GAUI_2_100GBASE_CR2_KR2_LEN,
1815763ece86SDanielle Ratson 		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_2X,
18162be5c8a9SAmit Cohen 		.speed		= SPEED_100000,
1817763ece86SDanielle Ratson 		.width		= 2,
18182be5c8a9SAmit Cohen 	},
18192be5c8a9SAmit Cohen 	{
18202be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_200GAUI_4_200GBASE_CR4_KR4,
18212be5c8a9SAmit Cohen 		.mask_ethtool	= mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4,
18222be5c8a9SAmit Cohen 		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_200GAUI_4_200GBASE_CR4_KR4_LEN,
1823763ece86SDanielle Ratson 		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_4X |
18242be5c8a9SAmit Cohen 				  MLXSW_SP_PORT_MASK_WIDTH_8X,
18252be5c8a9SAmit Cohen 		.speed		= SPEED_200000,
1826763ece86SDanielle Ratson 		.width		= 4,
18272be5c8a9SAmit Cohen 	},
18282be5c8a9SAmit Cohen 	{
18292be5c8a9SAmit Cohen 		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_400GAUI_8,
18302be5c8a9SAmit Cohen 		.mask_ethtool	= mlxsw_sp2_mask_ethtool_400gaui_8,
18312be5c8a9SAmit Cohen 		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_400GAUI_8_LEN,
1832763ece86SDanielle Ratson 		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_8X,
18332be5c8a9SAmit Cohen 		.speed		= SPEED_400000,
1834763ece86SDanielle Ratson 		.width		= 8,
18352be5c8a9SAmit Cohen 	},
1836*cceef209SAmit Cohen 	{
1837*cceef209SAmit Cohen 		.mask		= MLXSW_REG_PTYS_EXT_ETH_SPEED_800GAUI_8,
1838*cceef209SAmit Cohen 		.mask_ethtool	= mlxsw_sp2_mask_ethtool_800gaui_8,
1839*cceef209SAmit Cohen 		.m_ethtool_len	= MLXSW_SP2_MASK_ETHTOOL_800GAUI_8_LEN,
1840*cceef209SAmit Cohen 		.mask_sup_width	= MLXSW_SP_PORT_MASK_WIDTH_8X,
1841*cceef209SAmit Cohen 		.speed		= SPEED_800000,
1842*cceef209SAmit Cohen 		.width		= 8,
1843*cceef209SAmit Cohen 	},
18442be5c8a9SAmit Cohen };
18452be5c8a9SAmit Cohen 
18462be5c8a9SAmit Cohen #define MLXSW_SP2_PORT_LINK_MODE_LEN ARRAY_SIZE(mlxsw_sp2_port_link_mode)
18472be5c8a9SAmit Cohen 
18482be5c8a9SAmit Cohen static void
mlxsw_sp2_from_ptys_supported_port(struct mlxsw_sp * mlxsw_sp,u32 ptys_eth_proto,struct ethtool_link_ksettings * cmd)18492be5c8a9SAmit Cohen mlxsw_sp2_from_ptys_supported_port(struct mlxsw_sp *mlxsw_sp,
18502be5c8a9SAmit Cohen 				   u32 ptys_eth_proto,
18512be5c8a9SAmit Cohen 				   struct ethtool_link_ksettings *cmd)
18522be5c8a9SAmit Cohen {
18532be5c8a9SAmit Cohen 	ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
18542be5c8a9SAmit Cohen 	ethtool_link_ksettings_add_link_mode(cmd, supported, Backplane);
18552be5c8a9SAmit Cohen }
18562be5c8a9SAmit Cohen 
18572be5c8a9SAmit Cohen static void
mlxsw_sp2_set_bit_ethtool(const struct mlxsw_sp2_port_link_mode * link_mode,unsigned long * mode)18582be5c8a9SAmit Cohen mlxsw_sp2_set_bit_ethtool(const struct mlxsw_sp2_port_link_mode *link_mode,
18592be5c8a9SAmit Cohen 			  unsigned long *mode)
18602be5c8a9SAmit Cohen {
18612be5c8a9SAmit Cohen 	int i;
18622be5c8a9SAmit Cohen 
18632be5c8a9SAmit Cohen 	for (i = 0; i < link_mode->m_ethtool_len; i++)
18642be5c8a9SAmit Cohen 		__set_bit(link_mode->mask_ethtool[i], mode);
18652be5c8a9SAmit Cohen }
18662be5c8a9SAmit Cohen 
18672be5c8a9SAmit Cohen static void
mlxsw_sp2_from_ptys_link(struct mlxsw_sp * mlxsw_sp,u32 ptys_eth_proto,unsigned long * mode)18682be5c8a9SAmit Cohen mlxsw_sp2_from_ptys_link(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto,
18695fc4053dSDanielle Ratson 			 unsigned long *mode)
18702be5c8a9SAmit Cohen {
18712be5c8a9SAmit Cohen 	int i;
18722be5c8a9SAmit Cohen 
18732be5c8a9SAmit Cohen 	for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
18745fc4053dSDanielle Ratson 		if (ptys_eth_proto & mlxsw_sp2_port_link_mode[i].mask)
18752be5c8a9SAmit Cohen 			mlxsw_sp2_set_bit_ethtool(&mlxsw_sp2_port_link_mode[i],
18762be5c8a9SAmit Cohen 						  mode);
18772be5c8a9SAmit Cohen 	}
18782be5c8a9SAmit Cohen }
18792be5c8a9SAmit Cohen 
18802be5c8a9SAmit Cohen static u32
mlxsw_sp2_from_ptys_speed(struct mlxsw_sp * mlxsw_sp,u32 ptys_eth_proto)18812be5c8a9SAmit Cohen mlxsw_sp2_from_ptys_speed(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto)
18822be5c8a9SAmit Cohen {
18832be5c8a9SAmit Cohen 	int i;
18842be5c8a9SAmit Cohen 
18852be5c8a9SAmit Cohen 	for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
18862be5c8a9SAmit Cohen 		if (ptys_eth_proto & mlxsw_sp2_port_link_mode[i].mask)
18872be5c8a9SAmit Cohen 			return mlxsw_sp2_port_link_mode[i].speed;
18882be5c8a9SAmit Cohen 	}
18892be5c8a9SAmit Cohen 
18902be5c8a9SAmit Cohen 	return SPEED_UNKNOWN;
18912be5c8a9SAmit Cohen }
18922be5c8a9SAmit Cohen 
18932be5c8a9SAmit Cohen static void
mlxsw_sp2_from_ptys_link_mode(struct mlxsw_sp * mlxsw_sp,bool carrier_ok,u32 ptys_eth_proto,struct ethtool_link_ksettings * cmd)189425a96f05SDanielle Ratson mlxsw_sp2_from_ptys_link_mode(struct mlxsw_sp *mlxsw_sp, bool carrier_ok,
18952be5c8a9SAmit Cohen 			      u32 ptys_eth_proto,
18962be5c8a9SAmit Cohen 			      struct ethtool_link_ksettings *cmd)
18972be5c8a9SAmit Cohen {
189825a96f05SDanielle Ratson 	struct mlxsw_sp2_port_link_mode link;
189925a96f05SDanielle Ratson 	int i;
190025a96f05SDanielle Ratson 
1901a975d7d8SDanielle Ratson 	cmd->base.speed = SPEED_UNKNOWN;
1902a975d7d8SDanielle Ratson 	cmd->base.duplex = DUPLEX_UNKNOWN;
1903a975d7d8SDanielle Ratson 	cmd->lanes = 0;
19042be5c8a9SAmit Cohen 
19052be5c8a9SAmit Cohen 	if (!carrier_ok)
19062be5c8a9SAmit Cohen 		return;
19072be5c8a9SAmit Cohen 
190825a96f05SDanielle Ratson 	for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
190925a96f05SDanielle Ratson 		if (ptys_eth_proto & mlxsw_sp2_port_link_mode[i].mask) {
191025a96f05SDanielle Ratson 			link = mlxsw_sp2_port_link_mode[i];
1911a975d7d8SDanielle Ratson 			ethtool_params_from_link_mode(cmd,
1912a975d7d8SDanielle Ratson 						      link.mask_ethtool[1]);
191325a96f05SDanielle Ratson 		}
191425a96f05SDanielle Ratson 	}
19152be5c8a9SAmit Cohen }
19162be5c8a9SAmit Cohen 
mlxsw_sp2_ptys_max_speed(struct mlxsw_sp_port * mlxsw_sp_port,u32 * p_max_speed)191760fbc521SPetr Machata static int mlxsw_sp2_ptys_max_speed(struct mlxsw_sp_port *mlxsw_sp_port, u32 *p_max_speed)
191860fbc521SPetr Machata {
191960fbc521SPetr Machata 	u32 eth_proto_cap;
192060fbc521SPetr Machata 	u32 max_speed = 0;
192160fbc521SPetr Machata 	int err;
192260fbc521SPetr Machata 	int i;
192360fbc521SPetr Machata 
192460fbc521SPetr Machata 	err = mlxsw_sp_port_ptys_query(mlxsw_sp_port, &eth_proto_cap, NULL, NULL, NULL);
192560fbc521SPetr Machata 	if (err)
192660fbc521SPetr Machata 		return err;
192760fbc521SPetr Machata 
192860fbc521SPetr Machata 	for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
192960fbc521SPetr Machata 		if ((eth_proto_cap & mlxsw_sp2_port_link_mode[i].mask) &&
193060fbc521SPetr Machata 		    mlxsw_sp2_port_link_mode[i].speed > max_speed)
193160fbc521SPetr Machata 			max_speed = mlxsw_sp2_port_link_mode[i].speed;
193260fbc521SPetr Machata 	}
193360fbc521SPetr Machata 
193460fbc521SPetr Machata 	*p_max_speed = max_speed;
193560fbc521SPetr Machata 	return 0;
193660fbc521SPetr Machata }
193760fbc521SPetr Machata 
19382be5c8a9SAmit Cohen static bool
mlxsw_sp2_test_bit_ethtool(const struct mlxsw_sp2_port_link_mode * link_mode,const unsigned long * mode)19392be5c8a9SAmit Cohen mlxsw_sp2_test_bit_ethtool(const struct mlxsw_sp2_port_link_mode *link_mode,
19402be5c8a9SAmit Cohen 			   const unsigned long *mode)
19412be5c8a9SAmit Cohen {
19422be5c8a9SAmit Cohen 	int cnt = 0;
19432be5c8a9SAmit Cohen 	int i;
19442be5c8a9SAmit Cohen 
19452be5c8a9SAmit Cohen 	for (i = 0; i < link_mode->m_ethtool_len; i++) {
19462be5c8a9SAmit Cohen 		if (test_bit(link_mode->mask_ethtool[i], mode))
19472be5c8a9SAmit Cohen 			cnt++;
19482be5c8a9SAmit Cohen 	}
19492be5c8a9SAmit Cohen 
19502be5c8a9SAmit Cohen 	return cnt == link_mode->m_ethtool_len;
19512be5c8a9SAmit Cohen }
19522be5c8a9SAmit Cohen 
19532be5c8a9SAmit Cohen static u32
mlxsw_sp2_to_ptys_advert_link(struct mlxsw_sp * mlxsw_sp,const struct ethtool_link_ksettings * cmd)19545fc4053dSDanielle Ratson mlxsw_sp2_to_ptys_advert_link(struct mlxsw_sp *mlxsw_sp,
19552be5c8a9SAmit Cohen 			      const struct ethtool_link_ksettings *cmd)
19562be5c8a9SAmit Cohen {
19572be5c8a9SAmit Cohen 	u32 ptys_proto = 0;
19582be5c8a9SAmit Cohen 	int i;
19592be5c8a9SAmit Cohen 
19602be5c8a9SAmit Cohen 	for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
19615fc4053dSDanielle Ratson 		if (mlxsw_sp2_test_bit_ethtool(&mlxsw_sp2_port_link_mode[i],
19622be5c8a9SAmit Cohen 					       cmd->link_modes.advertising))
19632be5c8a9SAmit Cohen 			ptys_proto |= mlxsw_sp2_port_link_mode[i].mask;
19642be5c8a9SAmit Cohen 	}
19652be5c8a9SAmit Cohen 	return ptys_proto;
19662be5c8a9SAmit Cohen }
19672be5c8a9SAmit Cohen 
mlxsw_sp2_to_ptys_speed_lanes(struct mlxsw_sp * mlxsw_sp,u8 width,const struct ethtool_link_ksettings * cmd)1968763ece86SDanielle Ratson static u32 mlxsw_sp2_to_ptys_speed_lanes(struct mlxsw_sp *mlxsw_sp, u8 width,
1969763ece86SDanielle Ratson 					 const struct ethtool_link_ksettings *cmd)
19702be5c8a9SAmit Cohen {
19712be5c8a9SAmit Cohen 	u8 mask_width = mlxsw_sp_port_mask_width_get(width);
1972763ece86SDanielle Ratson 	struct mlxsw_sp2_port_link_mode link_mode;
19732be5c8a9SAmit Cohen 	u32 ptys_proto = 0;
19742be5c8a9SAmit Cohen 	int i;
19752be5c8a9SAmit Cohen 
1976763ece86SDanielle Ratson 	if (cmd->lanes > width)
1977763ece86SDanielle Ratson 		return ptys_proto;
1978763ece86SDanielle Ratson 
19792be5c8a9SAmit Cohen 	for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
1980763ece86SDanielle Ratson 		if (cmd->base.speed == mlxsw_sp2_port_link_mode[i].speed) {
1981763ece86SDanielle Ratson 			link_mode = mlxsw_sp2_port_link_mode[i];
1982763ece86SDanielle Ratson 
1983763ece86SDanielle Ratson 			if (!cmd->lanes) {
1984763ece86SDanielle Ratson 				/* If number of lanes was not set by user space,
1985763ece86SDanielle Ratson 				 * choose the link mode that supports the width
1986763ece86SDanielle Ratson 				 * of the port.
1987763ece86SDanielle Ratson 				 */
1988763ece86SDanielle Ratson 				if (mask_width & link_mode.mask_sup_width)
1989763ece86SDanielle Ratson 					ptys_proto |= link_mode.mask;
1990763ece86SDanielle Ratson 			} else if (cmd->lanes == link_mode.width) {
1991763ece86SDanielle Ratson 				/* Else if the number of lanes was set, choose
1992763ece86SDanielle Ratson 				 * the link mode that its actual width equals to
1993763ece86SDanielle Ratson 				 * it.
1994763ece86SDanielle Ratson 				 */
1995763ece86SDanielle Ratson 				ptys_proto |= link_mode.mask;
1996763ece86SDanielle Ratson 			}
1997763ece86SDanielle Ratson 		}
19982be5c8a9SAmit Cohen 	}
19992be5c8a9SAmit Cohen 	return ptys_proto;
20002be5c8a9SAmit Cohen }
20012be5c8a9SAmit Cohen 
20022be5c8a9SAmit Cohen static void
mlxsw_sp2_reg_ptys_eth_pack(struct mlxsw_sp * mlxsw_sp,char * payload,u16 local_port,u32 proto_admin,bool autoneg)20032be5c8a9SAmit Cohen mlxsw_sp2_reg_ptys_eth_pack(struct mlxsw_sp *mlxsw_sp, char *payload,
2004c934757dSAmit Cohen 			    u16 local_port, u32 proto_admin,
20052be5c8a9SAmit Cohen 			    bool autoneg)
20062be5c8a9SAmit Cohen {
20072be5c8a9SAmit Cohen 	mlxsw_reg_ptys_ext_eth_pack(payload, local_port, proto_admin, autoneg);
20082be5c8a9SAmit Cohen }
20092be5c8a9SAmit Cohen 
20102be5c8a9SAmit Cohen static void
mlxsw_sp2_reg_ptys_eth_unpack(struct mlxsw_sp * mlxsw_sp,char * payload,u32 * p_eth_proto_cap,u32 * p_eth_proto_admin,u32 * p_eth_proto_oper)20112be5c8a9SAmit Cohen mlxsw_sp2_reg_ptys_eth_unpack(struct mlxsw_sp *mlxsw_sp, char *payload,
20122be5c8a9SAmit Cohen 			      u32 *p_eth_proto_cap, u32 *p_eth_proto_admin,
20132be5c8a9SAmit Cohen 			      u32 *p_eth_proto_oper)
20142be5c8a9SAmit Cohen {
20152be5c8a9SAmit Cohen 	mlxsw_reg_ptys_ext_eth_unpack(payload, p_eth_proto_cap,
20162be5c8a9SAmit Cohen 				      p_eth_proto_admin, p_eth_proto_oper);
20172be5c8a9SAmit Cohen }
20182be5c8a9SAmit Cohen 
mlxsw_sp2_ptys_proto_cap_masked_get(u32 eth_proto_cap)20191601559bSAmit Cohen static u32 mlxsw_sp2_ptys_proto_cap_masked_get(u32 eth_proto_cap)
20201601559bSAmit Cohen {
20211601559bSAmit Cohen 	u32 ptys_proto_cap_masked = 0;
20221601559bSAmit Cohen 	int i;
20231601559bSAmit Cohen 
20241601559bSAmit Cohen 	for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
20251601559bSAmit Cohen 		if (mlxsw_sp2_port_link_mode[i].mask & eth_proto_cap)
20261601559bSAmit Cohen 			ptys_proto_cap_masked |=
20271601559bSAmit Cohen 				mlxsw_sp2_port_link_mode[i].mask;
20281601559bSAmit Cohen 	}
20291601559bSAmit Cohen 
20301601559bSAmit Cohen 	return ptys_proto_cap_masked;
20311601559bSAmit Cohen }
20321601559bSAmit Cohen 
20332be5c8a9SAmit Cohen const struct mlxsw_sp_port_type_speed_ops mlxsw_sp2_port_type_speed_ops = {
20342be5c8a9SAmit Cohen 	.from_ptys_supported_port	= mlxsw_sp2_from_ptys_supported_port,
20352be5c8a9SAmit Cohen 	.from_ptys_link			= mlxsw_sp2_from_ptys_link,
20362be5c8a9SAmit Cohen 	.from_ptys_speed		= mlxsw_sp2_from_ptys_speed,
203725a96f05SDanielle Ratson 	.from_ptys_link_mode		= mlxsw_sp2_from_ptys_link_mode,
203860fbc521SPetr Machata 	.ptys_max_speed			= mlxsw_sp2_ptys_max_speed,
20392be5c8a9SAmit Cohen 	.to_ptys_advert_link		= mlxsw_sp2_to_ptys_advert_link,
2040763ece86SDanielle Ratson 	.to_ptys_speed_lanes		= mlxsw_sp2_to_ptys_speed_lanes,
20412be5c8a9SAmit Cohen 	.reg_ptys_eth_pack		= mlxsw_sp2_reg_ptys_eth_pack,
20422be5c8a9SAmit Cohen 	.reg_ptys_eth_unpack		= mlxsw_sp2_reg_ptys_eth_unpack,
20431601559bSAmit Cohen 	.ptys_proto_cap_masked_get	= mlxsw_sp2_ptys_proto_cap_masked_get,
20442be5c8a9SAmit Cohen };
2045